Help detect when relacy_std is not included first#38
Conversation
f7bb5c7 to
b0296bf
Compare
|
CI passed -- easier to merge. Thanks! |
Yes! In fact, my original attempt at this broke the C++11 build and CI caught it, since I had only tested C++23 locally. |
|
On Wed, Jan 21, 2026 at 7:53 AM Chris Cotter ***@***.***> wrote:
*ccotter* left a comment (dvyukov/relacy#38)
<#38 (comment)>
CI passed -- easier to merge. Thanks!
Yes! In fact, my original attempt at this broke the C++11 build and CI
caught it, since I had only tested C++23 locally.
—
Using rl namespace is fine. Not sure why it needs to be fully integrated
into the std namespace. Well, I am an old school relacy user from back in
comp.programming.threads when it was being developed.
… Message ID: ***@***.***>
|
I can attest to that 🙂 |
|
On Wed, Jan 21, 2026 at 10:56 PM Dmitry Vyukov ***@***.***> wrote:
*dvyukov* left a comment (dvyukov/relacy#38)
<#38 (comment)>
Well, I am an old school relacy user from back in comp.programming.threads
when it was being developed.
I can attest to that 🙂
It was a fun time back then! Btw, what is the most recent version of
Relacy? I have an older one that works fine.
Btw, did you ever model futex? I think you might have already.
Also, rl:: namespace is fine. Perhaps Relacy should not be trying to inject
itself into the std namespace?
… Message ID: ***@***.***>
|
Indeed!
Now it's just on github with "continuous release".
No, I don't think so.
I think that's useful to make fewer changes to the existing code. |
|
On Mon, Feb 2, 2026 at 11:52 PM Dmitry Vyukov ***@***.***> wrote:
*dvyukov* left a comment (dvyukov/relacy#38)
<#38 (comment)>
Well, I am an old school relacy user from back in comp.programming.threads
when it was being developed.
I can attest to that 🙂
It was a fun time back then!
Indeed!
Btw, what is the most recent version of Relacy? I have an older one that
works fine.
Now it's just on github with "continuous release".
You can always pull the latest version from
https://github.com/dvyukov/relacy.git
@ccotter <https://github.com/ccotter> kindly contributed github actions
that build/test every commit, so hopefully it even works :)
Btw, did you ever model futex?
No, I don't think so.
I think you might have already. Also, rl:: namespace is fine. Perhaps
Relacy should not be trying to inject itself into the std namespace?
Wrt futex, I am getting some memories. Shit, so busy with other work now.
I vaguely remember some of my tests where I think I did make a futex in
Relacy. But, I never used the "integration", rl::* was fine with me.
Putting into std::*, well, get ready for a shit load of worms jumping out
of the can... ;^D
I think that's useful to make fewer changes to the existing code.
Fair enough. It's just, well, it's a bitch now. Relacy was before C++11...
Trying to pull all/some of Relacy into the std::* namespace can make things
go very odd, and well, shit man. ;^o
Fwiw, I created a little test for a highly experimental stack mixed with a
mutex. It uses a futex, but I wanted to test it in Relacy. Alas, no futex.
Just busy doing other things. Fwiw, here is my code in question:
…_____________
This is a little C++20 test using a futex to allow one to wait on a
lock-free stack. The main stack logic is in struct ct_stack. Well, can you
get to compile and run? Thanks...
I still need to check my algorithm out in Relacy. I think it might be able
to model futex.
My code:
______________________________________
#include <iostream>
#include <thread>
#include <atomic>
#include <algorithm>
#include <cassert>
#define CT_THREAD_N (42)
#define CT_WORK_N (10000000)
#define CT_WAIT ((ct_node*)0xDEADBEEF)
struct ct_node
{
ct_node* m_next = { nullptr };
ct_node()
{
//std::cout << "(" << this << ")::ct_node::ct_node()\n";
}
~ct_node()
{
//std::cout << "(" << this << ")::ct_node::~ct_node()\n";
}
};
struct ct_stack
{
std::atomic<ct_node*> m_head = { nullptr };
void
push(
ct_node* node
) {
ct_node* head = m_head.load(std::memory_order_relaxed);
do
{
if (head == CT_WAIT)
{
node->m_next = nullptr;
}
else
{
node->m_next = head;
}
} while (! m_head.compare_exchange_weak(
head,
node,
std::memory_order_release)
);
if (head == CT_WAIT)
{
// slow path...
m_head.notify_one();
}
}
ct_node*
flush_wait()
{
ct_node* head = nullptr;
for (;;)
{
head = m_head.exchange(nullptr, std::memory_order_acquire);
while (! head || head == CT_WAIT)
{
// slow path...
head = m_head.exchange(CT_WAIT, std::memory_order_acquire);
if (! head || head == CT_WAIT)
{
m_head.wait(CT_WAIT, std::memory_order_relaxed);
continue;
}
}
break;
}
assert(head && head != CT_WAIT);
return head;
}
};
struct ct_work : public ct_node
{
unsigned long m_state = { 0 };
};
struct ct_shared
{
ct_stack m_stack_in;
ct_stack m_stack_out;
ct_shared()
{
std::cout << "ct_shared::ct_shared()\n" << std::endl;
}
~ct_shared()
{
assert(! m_stack_in.m_head || m_stack_in.m_head == CT_WAIT);
assert(! m_stack_out.m_head || m_stack_out.m_head == CT_WAIT);
std::cout << "ct_shared::~ct_shared()\n" << std::endl;
}
};
void
ct_thread(
ct_shared& shared
) {
unsigned long state = 0;
while (! state)
{
ct_work* head = (ct_work*)shared.m_stack_in.flush_wait();
while (head)
{
ct_work* next = (ct_work*)head->m_next;
if (head->m_state == 666)
{
// Shutdown detected...
state = 1;
shared.m_stack_in.push(head);
}
else
{
shared.m_stack_out.push(head);
}
head = next;
}
}
//std::cout << "shutdown..." << std::endl;
}
int
main()
{
{
std::cout << "Futex Stack Test\n";
std::cout << "by: Chris M. Thomasson\n";
std::cout << "version: (0.0.1)\n";
std::cout << "_________________________________\n" << std::endl;
}
unsigned long g_ct_work_alloations = 0;
unsigned long g_ct_work_dealloations = 0;
{
std::cout << "CT_THREAD_N = " << CT_THREAD_N << std::endl;
std::cout << "CT_WORK_N = " << CT_WORK_N << std::endl;
std::cout << "CT_WAIT = " << CT_WAIT << std::endl;
}
{
ct_shared shared = { };
std::thread threads[CT_THREAD_N];
std::cout << "\nLaunching threads...\n" << std::endl;
for (unsigned long i = 0; i < CT_THREAD_N; ++i)
{
threads[i] = std::thread(ct_thread, std::ref(shared));
}
//std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "\nGenerate work...\n" << std::endl;
// Generate work...
{
for (unsigned long i = 0; i < CT_WORK_N; ++i)
{
shared.m_stack_in.push(new ct_work);
++g_ct_work_alloations;
}
}
// Wait for work...
{
unsigned long wn = 0;
while (wn < CT_WORK_N)
{
ct_work* head = (ct_work*)shared.m_stack_out.flush_wait();
while (head)
{
ct_work* next = (ct_work*)head->m_next;
delete head;
++g_ct_work_dealloations;
++wn;
head = next;
}
}
}
std::cout << "\nCompleted all work!\n" << std::endl;
std::cout << "Sending shutdown state...\n" << std::endl;
// Send shutdown state...
{
for (unsigned long i = 0; i < CT_THREAD_N; ++i)
{
ct_work* w = new ct_work;
++g_ct_work_alloations;
w->m_state = 666;
shared.m_stack_in.push(w);
}
}
// Join threads...
{
for (unsigned long i = 0; i < CT_THREAD_N; ++i)
{
threads[i].join();
}
}
std::cout << "\nThreads joined...\n" << std::endl;
// Dump shutdown state...
std::cout << "Dump shutdown state...\n" << std::endl;
{
ct_work* head =
(ct_work*)shared.m_stack_in.m_head.load(std::memory_order_relaxed);
shared.m_stack_in.m_head = nullptr;
while (head)
{
ct_work* next = (ct_work*)head->m_next;
delete head;
++g_ct_work_dealloations;
head = next;
}
}
std::cout << "\nShutdown complete!\n" << std::endl;
}
// Sanity check...
{
std::cout << "g_ct_work_alloations = " << g_ct_work_alloations <<
"\n";
std::cout << "g_ct_work_dealloations = " << g_ct_work_dealloations
<< std::endl;
if (g_ct_work_alloations != g_ct_work_dealloations)
{
std::cout << "Pardon my French, but shit!!!!!!!!!!!!!! NOT
GOOD\n" << std::endl;
std::cout << "DAMN IT!!!! Grrrrr\n" << std::endl;
}
}
std::cout << "\nFin!\n" << std::endl;
return 0;
}
______________________________________
My output:
_______________________
Futex Stack Test
by: Chris M. Thomasson
version: (0.0.1)
_________________________________
CT_THREAD_N = 42
CT_WORK_N = 10000000
CT_WAIT = 00000000DEADBEEF
ct_shared::ct_shared()
Launching threads...
Generate work...
Completed all work!
Sending shutdown state...
Threads joined...
Dump shutdown state...
Shutdown complete!
ct_shared::~ct_shared()
g_ct_work_alloations = 10000042
g_ct_work_dealloations = 10000042
Fin!
_______________________
Well, any luck?
;^)
Message ID: ***@***.***>
|
Mr lock-free strikes back! 🙂 For ThreadSanitizer race detector we did proper compiler instrumentation and runtime support. It does not require any code changes whatsoever. But it always lacked more precise memory model simulation and random scheduling. Ideally there is only one tool that can do both (nice compiler instrumentation + memory model + scheduling). @ccotter already kindly started adding better scheduling to TSan (note to myself: review it!): |
No description provided.