Spice up signal-test tool

This commit is contained in:
Robin Gareus 2021-11-21 08:27:46 +01:00
parent beddcf1a01
commit f112697be8
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
1 changed files with 157 additions and 31 deletions

View File

@ -1,27 +1,35 @@
#include <cstdint> #include <cassert>
#include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <getopt.h>
#include <pthread.h> #include <pthread.h>
#include "pbd/pbd.h"
#include "pbd/signals.h"
#include "pbd/event_loop.h" #include "pbd/event_loop.h"
#include "pbd/pbd.h"
#include "pbd/pcg_rand.h"
#include "pbd/signals.h"
class Tx { class Tx
{
public: public:
PBD::Signal1<void, int> sig1; PBD::Signal1<void, int> sig1;
}; };
/* ****************************************************************************/ /* ****************************************************************************/
class Rx1 { class Rx1
{
public: public:
Rx1 (Tx& sender) { Rx1 (Tx& sender)
{
sender.sig1.connect_same_thread (_connection, boost::bind (&Rx1::cb, this, _1)); sender.sig1.connect_same_thread (_connection, boost::bind (&Rx1::cb, this, _1));
} }
private: private:
void cb (int i) { void cb (int i)
printf ("Rx1 %d\n", i); {
printf ("Rx1(%d) ", i);
} }
PBD::ScopedConnection _connection; PBD::ScopedConnection _connection;
@ -29,24 +37,63 @@ private:
/* ****************************************************************************/ /* ****************************************************************************/
struct MyInvalidationRecord : public PBD::EventLoop::InvalidationRecord class MyEventLoop : public sigc::trackable, public PBD::EventLoop
{ {
~MyInvalidationRecord () { public:
MyEventLoop (std::string const& name)
: EventLoop (name)
{
run_loop_thread = Glib::Threads::Thread::self ();
}
void call_slot (InvalidationRecord* ir, const boost::function<void ()>& f)
{
if (Glib::Threads::Thread::self () == run_loop_thread) {
f ();
} else {
assert (!ir);
assert (0);
f (); // XXX really queue and process during run ()
}
}
void run ()
{
; // process Events, if any
}
Glib::Threads::Mutex& slot_invalidation_mutex ()
{
return request_buffer_map_lock;
}
private:
Glib::Threads::Thread* run_loop_thread;
Glib::Threads::Mutex request_buffer_map_lock;
};
struct MyInvalidationRecord : public PBD::EventLoop::InvalidationRecord {
~MyInvalidationRecord ()
{
assert (use_count () == 0); assert (use_count () == 0);
} }
}; };
MyInvalidationRecord _ir; static MyEventLoop event_loop ("foo");
static MyInvalidationRecord _ir;
class Rx2 : public PBD::ScopedConnectionList { class Rx2 : public PBD::ScopedConnectionList
{
public: public:
Rx2 (Tx& sender) { Rx2 (Tx& sender)
sender.sig1.connect (*this, &_ir, boost::bind (&Rx2::cb, this, _1), /* PBD::EventLoop */ 0); {
sender.sig1.connect (*this, &_ir, boost::bind (&Rx2::cb, this, _1), &event_loop);
} }
private: private:
void cb (int i) { void cb (int i)
printf ("CB %d\n", i); {
printf ("Rx2(%d) ", i);
} }
}; };
@ -54,51 +101,130 @@ private:
pthread_barrier_t barrier; pthread_barrier_t barrier;
static void* delete_tx (void* arg) { static void*
delete_tx (void* arg)
{
Tx* tx = static_cast<Tx*> (arg); Tx* tx = static_cast<Tx*> (arg);
pthread_barrier_wait (&barrier); pthread_barrier_wait (&barrier);
delete tx; delete tx;
//printf ("Deleted tx\n");
return 0; return 0;
} }
static void* delete_rx1 (void* arg) { static void*
delete_rx1 (void* arg)
{
Rx1* rx1 = static_cast<Rx1*> (arg); Rx1* rx1 = static_cast<Rx1*> (arg);
pthread_barrier_wait (&barrier); pthread_barrier_wait (&barrier);
delete rx1; delete rx1;
//printf ("Deleted rx1\n");
return 0; return 0;
} }
static void* delete_rx2 (void* arg) { static void*
delete_rx2 (void* arg)
{
Rx2* rx2 = static_cast<Rx2*> (arg); Rx2* rx2 = static_cast<Rx2*> (arg);
pthread_barrier_wait (&barrier); pthread_barrier_wait (&barrier);
delete rx2; delete rx2;
//printf ("Deleted rx2\n");
return 0; return 0;
} }
/* ****************************************************************************/ /* ****************************************************************************/
int static PBD::PCGRand pcg;
main (int argc, char** argv) static bool emit_signal = false;
static void
run_test ()
{ {
PBD::init (); Tx* tx = new Tx ();
Tx* tx = new Tx ();
Rx1* rx1 = new Rx1 (*tx); Rx1* rx1 = new Rx1 (*tx);
Rx2* rx2 = new Rx2 (*tx); Rx2* rx2 = new Rx2 (*tx);
pthread_barrier_init (&barrier, NULL, 3); /* randomize thread start, not that it matters much since
pthread_t t[3]; * pthread_barrier_wait() leaves it undefined which thread
* continues with PTHREAD_BARRIER_SERIAL_THREAD, but some
* implementations may special-case the last */
static int rnd[3] = { 0, 1, 2 };
for (int i = 2; i > 0; --i) {
int j = pcg.rand (i + 1);
int tmp = rnd[i];
rnd[i] = rnd[j];
rnd[j] = tmp;
}
pthread_create (&t[0], NULL, delete_tx, (void*)tx); if (emit_signal) {
pthread_create (&t[1], NULL, delete_rx1, (void*)rx1); tx->sig1 (rnd[0]); /* EMIT SIGNAL */
pthread_create (&t[2], NULL, delete_rx2, (void*)rx2); }
pthread_t t[3];
for (int i = 0; i < 3; ++i) {
switch (rnd[i]) {
case 0:
pthread_create (&t[0], NULL, delete_tx, (void*)tx);
break;
case 1:
pthread_create (&t[1], NULL, delete_rx1, (void*)rx1);
break;
case 2:
pthread_create (&t[2], NULL, delete_rx2, (void*)rx2);
break;
}
}
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
pthread_join (t[i], NULL); pthread_join (t[i], NULL);
} }
if (emit_signal) {
printf ("\n");
}
}
int
main (int argc, char** argv)
{
int n_iter = 0;
const char* optstring = "ei:";
/* clang-format off */
const struct option longopts[] = {
{ "emit", no_argument, 0, 'e' },
{ "iterations", required_argument, 0, 'i' },
};
/* clang-format on */
int c = 0;
while (EOF != (c = getopt_long (argc, argv, optstring, longopts, (int*)0))) {
switch (c) {
case 'e':
emit_signal = true;
break;
case 'i':
n_iter = atoi (optarg);
break;
default:
fprintf (stderr, "Error: unrecognized option.\n");
::exit (EXIT_FAILURE);
break;
}
}
if (optind != argc) {
fprintf (stderr, "Error: unrecognized option.\n");
::exit (EXIT_FAILURE);
}
if (n_iter <= 0 || n_iter > 1000000) {
n_iter = 1000;
}
PBD::init ();
pthread_barrier_init (&barrier, NULL, 3);
for (int i = 0; i < n_iter; ++i) {
run_test ();
}
pthread_barrier_destroy (&barrier); pthread_barrier_destroy (&barrier);
PBD::cleanup (); PBD::cleanup ();
return 0; return 0;