From a9f5e0a528270424b47517ba677eb731a759a695 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 2 Mar 2018 11:26:25 +0100 Subject: [PATCH] non working ideas removed --- playground/invoker/Invoker.cpp | 28 +++++- playground/invoker/main.cpp | 159 ++++++++++++++++++-------------- src/common/QskMetaFunction.cpp | 116 ++++++++++++----------- src/common/QskMetaFunction.h | 26 ++---- src/common/QskMetaInvokable.cpp | 77 ---------------- src/common/QskMetaInvokable.h | 84 +++-------------- 6 files changed, 192 insertions(+), 298 deletions(-) diff --git a/playground/invoker/Invoker.cpp b/playground/invoker/Invoker.cpp index b1f55c3d..96c6bde0 100644 --- a/playground/invoker/Invoker.cpp +++ b/playground/invoker/Invoker.cpp @@ -4,6 +4,7 @@ *****************************************************************************/ #include "Invoker.h" +#include Invoker::Invoker( QObject* parent ): QObject( parent ) @@ -47,9 +48,28 @@ void Invoker::invoke( qreal realValue, int intValue, callback.setConnectionType( connectionType ); - if ( connectionType == Qt::DirectConnection ) - callback.invoke( args ); - else if ( callback.object() ) - callback.invoke( args ); + const int callType = connectionType & 0x3; + switch( callType ) + { + case Qt::DirectConnection: + { + callback.invoke( args ); + break; + } + case Qt::QueuedConnection: + { + if ( callback.object() ) + callback.invoke( args ); + break; + } + case Qt::BlockingQueuedConnection: + { + const auto receiver = callback.object(); + if ( receiver && receiver->thread() != QThread::currentThread() ) + callback.invoke( args ); + + break; + } + } } } diff --git a/playground/invoker/main.cpp b/playground/invoker/main.cpp index d4941395..fbac5c13 100644 --- a/playground/invoker/main.cpp +++ b/playground/invoker/main.cpp @@ -7,6 +7,7 @@ #include #include #include +#include static void debugNone1() { @@ -40,17 +41,20 @@ static void debugValue( qreal d, int i ) class MyObject : public QObject { - Q_OBJECT - public: MyObject( QObject* parent = nullptr ): QObject( parent ) { } + void print0( double d, int i ) const + { + qDebug() << "print0" << d << i; + } + void print1( double d, int i ) const { - qDebug() << d << i; + qDebug() << "print1" << d << i; } void print2( int i, double d ) const @@ -67,83 +71,96 @@ public: { qDebug() << i; } - -Q_SIGNALS: - void done( double, int ); -}; - -class MyObject2: public MyObject -{ -public: - MyObject2( QObject* parent = nullptr ): - MyObject( parent ) - { - } - - virtual ~MyObject2() - { - } - - virtual void noop() - { - } }; static auto fs = []( int i, double d ) { qDebug() << i << d; }; +class Application: public QCoreApplication +{ +public: + Application( int &argc, char *argv[] ): + QCoreApplication( argc, argv ), + m_object( new MyObject() ), + m_thread( new QThread( this ) ) + { + auto f = [this]( int i, double d ) { qDebug() << i << d << (++m_num); }; + + m_invoker.addCallback( m_object, &MyObject::print0 ); + m_invoker.addCallback( m_object, &MyObject::print1 ); + m_invoker.addCallback( QskMetaFunction() ); + m_invoker.addCallback( debugNone1 ); + m_invoker.addCallback( debugNone2 ); + m_invoker.addCallback( debugValue ); + m_invoker.addCallback( debugValueI1 ); + m_invoker.addCallback( debugValueI2 ); + m_invoker.addCallback( debugValueD ); + m_invoker.addCallback( m_object, &MyObject::print0 ); + m_invoker.addCallback( m_object, &MyObject::print1 ); + m_invoker.addCallback( m_object, &MyObject::print2 ); + m_invoker.addCallback( m_object, &MyObject::print3 ); + m_invoker.addCallback( m_object, &MyObject::print4 ); + m_invoker.addCallback( m_object, []( double d, int i ) { qDebug() << d << i; } ); + + m_invoker.addCallback( m_object, f ); + m_invoker.addCallback( m_object, fs ); + + m_invoker.addCallback( m_object, []( double d ) { qDebug() << d; } ); + m_invoker.addCallback( []() { qDebug() << "HERE"; } ); + m_invoker.addCallback( []( int i, double d ) { qDebug() << i << d; } ); + m_invoker.addCallback( []( int i ) { qDebug() << "I1" << i; } ); + m_invoker.addCallback( []( int i ) { qDebug() << "I2" << i; } ); + m_invoker.addCallback( []( double d ) { qDebug() << "V" << d; } ); + m_invoker.addCallback( []( const double& d ) { qDebug() << "R" << d; } ); + + } + + virtual ~Application() + { + delete m_object; + } + + void invokeDirect() + { + qDebug() << "== Direct Connections"; + m_invoker.invoke( 3.14, 35, Qt::DirectConnection ); + } + + void invokeQueued() + { + qDebug() << "== Queued Connections"; + m_invoker.invoke( 0.07, 42, Qt::QueuedConnection ); + } + + void invokeBlockingQueued() + { + m_thread->start(); + + m_object->moveToThread( m_thread ); + + qDebug() << "== Blocking Queued Connections"; + m_invoker.invoke( 0.54, 88, Qt::BlockingQueuedConnection ); + + QTimer::singleShot( 10, m_thread, &QThread::quit ); + } + +private: + Invoker m_invoker; + MyObject* m_object; + QThread* m_thread; + + int m_num = 111; +}; + int main( int argc, char* argv[] ) { - QCoreApplication app( argc, argv ); + Application app( argc, argv ); - MyObject object; - MyObject2 object2; + app.invokeDirect(); - int num = 111; - auto f = [&num]( int i, double d ) { qDebug() << i << d << (++num); }; + QTimer::singleShot( 0, &app, &Application::invokeQueued ); + QTimer::singleShot( 20, &app, &Application::invokeBlockingQueued ); - Invoker invoker; - -#if 1 - invoker.addCallback( QskMetaFunction() ); - invoker.addCallback( debugNone1 ); - invoker.addCallback( debugNone2 ); - invoker.addCallback( debugValue ); - invoker.addCallback( debugValueI1 ); - invoker.addCallback( debugValueI2 ); - invoker.addCallback( debugValueD ); - invoker.addCallback( &object, &MyObject::print1 ); - invoker.addCallback( &object2, &MyObject2::print1 ); - invoker.addCallback( &object, &MyObject::print2 ); - invoker.addCallback( &object, &MyObject::print3 ); - invoker.addCallback( &object, &MyObject::print4 ); - invoker.addCallback( &object, []( double d, int i ) { qDebug() << d << i; } ); - - invoker.addCallback( &object, f ); - invoker.addCallback( &object2, f ); - invoker.addCallback( &object, fs ); - invoker.addCallback( &object2, fs ); - - invoker.addCallback( &object, []( double d ) { qDebug() << d; } ); - invoker.addCallback( []() { qDebug() << "HERE"; } ); - invoker.addCallback( []( int i, double d ) { qDebug() << i << d; } ); - invoker.addCallback( []( int i ) { qDebug() << "I1" << i; } ); - invoker.addCallback( []( int i ) { qDebug() << "I2" << i; } ); - invoker.addCallback( []( double d ) { qDebug() << d; } ); -#endif - -#if 1 - qDebug() << "== Direct Connections"; - invoker.invoke( 3.14, 35, Qt::DirectConnection ); - - qDebug() << "\n\n== Queued Connections"; - - QTimer::singleShot( 0, - [&invoker] { invoker.invoke( 0.07, 42, Qt::QueuedConnection ); } ); -#endif - - QTimer::singleShot( 100, &app, QCoreApplication::quit ); + QTimer::singleShot( 50, &app, QCoreApplication::quit ); return app.exec(); } - -#include "main.moc" diff --git a/src/common/QskMetaFunction.cpp b/src/common/QskMetaFunction.cpp index 799bc539..f65f9710 100644 --- a/src/common/QskMetaFunction.cpp +++ b/src/common/QskMetaFunction.cpp @@ -33,13 +33,6 @@ QskMetaFunction::QskMetaFunction(): { } -QskMetaFunction::QskMetaFunction( void(*function)() ): - m_invokable( QskMetaInvokable::instance( - QskMetaFunctionInvokable0::invoke, nullptr, - reinterpret_cast< void** >( &function ) ) ) -{ -} - QskMetaFunction::QskMetaFunction( QskMetaInvokable* invokable ): m_invokable( invokable ) { @@ -122,6 +115,10 @@ QskMetaFunction::Type QskMetaFunction::functionType() const void QskMetaFunction::invoke( QObject* object, void* argv[], Qt::ConnectionType connectionType ) { + // code is not thread safe - TODO ... + + QPointer receiver( object ); + if ( m_invokable == nullptr ) return; @@ -129,72 +126,73 @@ void QskMetaFunction::invoke( if ( invokeType == Qt::AutoConnection ) { - invokeType = ( object && object->thread() != QThread::currentThread() ) + invokeType = ( receiver && receiver->thread() != QThread::currentThread() ) ? Qt::QueuedConnection : Qt::DirectConnection; } - else if ( invokeType == Qt::BlockingQueuedConnection ) + + switch( invokeType ) { - if ( ( object == nullptr ) || object->thread() == QThread::currentThread() ) + case Qt::DirectConnection: { - // We would end up in a deadlock, better do nothing - return; + m_invokable->call( receiver, argv ); + break; } - } - - if ( invokeType == Qt::DirectConnection ) - { - m_invokable->call( object, argv ); - } - else - { - if ( object == nullptr ) + case Qt::BlockingQueuedConnection: { -#if 1 - /* - object might be deleted in another thread - during this call - TODO ... - */ -#endif - return; - } - - const auto argc = parameterCount(); - - auto types = static_cast< int* >( malloc( argc * sizeof( int ) ) ); - auto arguments = static_cast< void** >( malloc( argc * sizeof( void* ) ) ); - - types[0] = QMetaType::UnknownType; // a return type is not possible - arguments[0] = nullptr; - - const int* parameterTypes = m_invokable->parameterTypes(); - for ( uint i = 1; i < argc; i++ ) - { - if ( argv[i] == nullptr ) + if ( receiver.isNull() + || ( receiver->thread() == QThread::currentThread() ) ) { - Q_ASSERT( arguments[i] != nullptr ); - - free( types ); - free( arguments ); - + // We would end up in a deadlock, better do nothing return; } - types[i] = parameterTypes[i - 1]; - arguments[i] = QMetaType::create( parameterTypes[i - 1], argv[i] ); - } - - if ( connectionType == Qt::QueuedConnection ) - { - qskInvokeFunctionQueued( object, m_invokable, argc, types, arguments ); - } - else // Qt::BlockingQueuedConnection ??? - { QSemaphore semaphore; - qskInvokeFunctionQueued( object, - m_invokable, argc, types, arguments, &semaphore ); + qskInvokeFunctionQueued( receiver, m_invokable, + 0, nullptr, argv, &semaphore ); semaphore.acquire(); + + break; + } + case Qt::QueuedConnection: + { + if ( receiver.isNull() ) + { + return; + } + + const auto argc = parameterCount(); + + auto types = static_cast< int* >( malloc( argc * sizeof( int ) ) ); + auto arguments = static_cast< void** >( malloc( argc * sizeof( void* ) ) ); + + types[0] = QMetaType::UnknownType; // a return type is not possible + arguments[0] = nullptr; + + const int* parameterTypes = m_invokable->parameterTypes(); + for ( uint i = 1; i < argc; i++ ) + { + if ( argv[i] == nullptr ) + { + Q_ASSERT( arguments[i] != nullptr ); + receiver = nullptr; + break; + } + + types[i] = parameterTypes[i - 1]; + arguments[i] = QMetaType::create( parameterTypes[i - 1], argv[i] ); + } + + if ( receiver.isNull() ) + { + // object might have died in the meantime + free( types ); + free( arguments ); + } + + qskInvokeFunctionQueued( object, m_invokable, argc, types, arguments ); + break; } } } diff --git a/src/common/QskMetaFunction.h b/src/common/QskMetaFunction.h index 951313d2..50690080 100644 --- a/src/common/QskMetaFunction.h +++ b/src/common/QskMetaFunction.h @@ -30,7 +30,6 @@ namespace QskMetaFunctionTraits template< typename T > using IsFunction0 = typename std::enable_if< !FunctionPointer< T >::IsPointerToMemberFunction && FunctionPointer< T >::ArgumentCount == 0, std::true_type >::type; - } class QSK_EXPORT QskMetaFunction @@ -59,8 +58,6 @@ public: QskMetaFunction( const QskMetaFunction& ); QskMetaFunction( QskMetaFunction&& ); - QskMetaFunction( void(*function)() ); - template< typename T, QskMetaFunctionTraits::IsMemberFunction< T >* = nullptr > QskMetaFunction( T ); @@ -115,10 +112,9 @@ inline QskMetaFunction::QskMetaFunction( T function ) constexpr int Argc = Traits::ArgumentCount; using Args = typename List_Left< typename Traits::Arguments, Argc >::Value; - m_invokable = QskMetaInvokable::instance( - QskMetaMemberInvokable< T, Args, void >::invoke, - ConnectionTypes< typename Traits::Arguments >::types(), - reinterpret_cast< void** >( &function ) ); + m_invokable = new QskMetaMemberInvokable< T, Args, void >( function ); + m_invokable->setParameterTypes( + ConnectionTypes< typename Traits::Arguments >::types() ); } template< typename T, QskMetaFunctionTraits::IsFunctor< T >* > @@ -131,10 +127,9 @@ inline QskMetaFunction::QskMetaFunction( T functor ) constexpr int Argc = Traits::ArgumentCount; using Args = typename List_Left< typename Traits::Arguments, Argc >::Value; - m_invokable = QskMetaInvokable::instance( - QskMetaFunctorInvokable< T, Argc, Args, void >::invoke, - ConnectionTypes< typename Traits::Arguments >::types(), - reinterpret_cast< void** >( &functor ) ); + m_invokable = new QskMetaFunctorInvokable< T, Argc, Args, void >( functor ); + m_invokable->setParameterTypes( + ConnectionTypes< typename Traits::Arguments >::types() ); } template< typename T, QskMetaFunctionTraits::IsFunction< T >* > @@ -146,11 +141,10 @@ inline QskMetaFunction::QskMetaFunction( T function ) constexpr int Argc = Traits::ArgumentCount; using Args = typename List_Left< typename Traits::Arguments, Argc >::Value; - - m_invokable = QskMetaInvokable::instance( - QskMetaFunctionInvokable< T, Args, void >::invoke, - ConnectionTypes< typename Traits::Arguments >::types(), - reinterpret_cast< void** >( &function ) ); + + m_invokable = new QskMetaFunctionInvokable< T, Args, void >( function ); + m_invokable->setParameterTypes( + ConnectionTypes< typename Traits::Arguments >::types() ); } Q_DECLARE_METATYPE( QskMetaFunction ) diff --git a/src/common/QskMetaInvokable.cpp b/src/common/QskMetaInvokable.cpp index 8182a1ce..0fe94821 100644 --- a/src/common/QskMetaInvokable.cpp +++ b/src/common/QskMetaInvokable.cpp @@ -19,39 +19,6 @@ namespace "Bad cast: QskMetaInvokable does not match" ); } -static inline void qskCallFunction( void (*function)(), - void** args, const int* types ) -{ - if ( types == nullptr || args == nullptr ) - { - function(); - return; - } -} - -QskMetaInvokable* QskMetaInvokable::instance( - InvokeFunction invoke, const int* parameterTypes, void** functor ) -{ - /* - In opposite to QObject::connect we share the Invokable for callbacks to the same - function/functor - like f.e QQuickItem::update(). But we have to pay an extra static - pointer inside of each callback instance. - */ - QskMetaInvokable* invokable; - void* args[] = { &invokable, functor }; - - invoke( Find, nullptr, nullptr, args, nullptr ); - - if ( invokable ) - invokable->ref(); - else - invoke( Create, nullptr, nullptr, args, nullptr ); - - invokable->m_parameterTypes = parameterTypes; - - return invokable; -} - int QskMetaInvokable::typeInfo() const { auto that = const_cast< QskMetaInvokable* >( this ); @@ -69,47 +36,3 @@ int QskMetaInvokable::refCount() const auto that = const_cast< QskMetaInvokable* >( this ); return reinterpret_cast< SlotObject* >( that )->ref.load(); } - -QskMetaFunctionInvokable0::QskMetaFunctionInvokable0( Function function ): - QskMetaInvokable( &invoke, nullptr ), - m_function( function ) -{ -} - -void QskMetaFunctionInvokable0::invoke(int which, QtPrivate::QSlotObjectBase* invokable, - QObject*, void** args, bool* ) -{ - switch ( which ) - { - case Find: - { - *reinterpret_cast< void** >( args[0] ) = nullptr; - break; - } - case Create: - { - *reinterpret_cast< void** >( args[0] ) = - new Invokable( *reinterpret_cast< Function* >( args[1] ) ); - - break; - } - case Destroy: - { - delete static_cast< Invokable* >( invokable ); - break; - } - case Call: - { - auto invokable01 = static_cast< Invokable* >( invokable ); - qskCallFunction( invokable01->m_function, - args, invokable01->parameterTypes() ); - - break; - } - case TypeInfo: - { - *reinterpret_cast< int* >( args ) = 1; // QskMetaFunction::Function - break; - } - } -} diff --git a/src/common/QskMetaInvokable.h b/src/common/QskMetaInvokable.h index 645de1fc..aeb85c7c 100644 --- a/src/common/QskMetaInvokable.h +++ b/src/common/QskMetaInvokable.h @@ -19,9 +19,7 @@ public: enum { - TypeInfo = NumOperations + 1, - Create, - Find + TypeInfo = NumOperations + 1 }; int typeInfo() const; @@ -32,8 +30,10 @@ public: return m_parameterTypes; } - static QskMetaInvokable* instance( InvokeFunction, - const int* parameterTypes, void** function ); + inline void setParameterTypes( const int* types ) + { + m_parameterTypes = types; + } protected: explicit inline QskMetaInvokable( InvokeFunction f, @@ -44,22 +44,7 @@ protected: } private: - const int* m_parameterTypes; // static array ! -}; - -class QSK_EXPORT QskMetaFunctionInvokable0 : public QskMetaInvokable -{ - using Function = void(*)(); - using Invokable = QskMetaFunctionInvokable0; - -public: - explicit QskMetaFunctionInvokable0( Function function ); - - static void invoke(int which, QtPrivate::QSlotObjectBase*, - QObject* object, void** args, bool* ); - -private: - Function m_function; + const int* m_parameterTypes; // static array, only needed for Qt::QueuedConnection }; template< typename Function, typename Args, typename R > @@ -79,18 +64,6 @@ public: { switch ( which ) { - case Find: - { - *reinterpret_cast< void** >( args[0] ) = nullptr; - break; - } - case Create: - { - *reinterpret_cast< void** >( args[0] ) = - new Invokable( *reinterpret_cast< Function* >( args[1] ) ); - - break; - } case Destroy: { delete static_cast< Invokable* >( invokable ); @@ -128,30 +101,14 @@ public: { } - static void invoke( int which, QtPrivate::QSlotObjectBase*, + static void invoke( int which, QtPrivate::QSlotObjectBase* slotObject, QObject* object, void** args, bool* ) { - static Invokable* invokable = nullptr; - switch (which) { - case Find: - { - *reinterpret_cast< void** >( args[0] ) = invokable; - break; - } - case Create: - { - invokable = new Invokable( *reinterpret_cast< Function* >( args[1] ) ); - *reinterpret_cast< void** >( args[0] ) = invokable; - - break; - } case Destroy: { - delete invokable; - invokable = nullptr; - + delete static_cast< Invokable* >( slotObject ); break; } case Call: @@ -159,7 +116,7 @@ public: typedef QtPrivate::FunctionPointer< Function > FuncType; FuncType::template call< Args, R >( - invokable->m_function, + static_cast< Invokable* >( slotObject )->m_function, static_cast< typename FuncType::Object* >( object ), args ); break; @@ -188,29 +145,14 @@ public: { } - static void invoke( int which, QSlotObjectBase*, QObject* object, void** args, bool* ) + static void invoke( int which, QSlotObjectBase* slotObject, + QObject* object, void** args, bool* ) { - static Invokable* invokable = nullptr; - switch (which) { - case Find: - { - *reinterpret_cast< void** >( args[0] ) = invokable; - break; - } - case Create: - { - invokable = new Invokable( *reinterpret_cast< Function* >( args[1] ) ); - *reinterpret_cast< void** >( args[0] ) = invokable; - - break; - } case Destroy: { - delete invokable; - invokable = nullptr; - + delete static_cast< Invokable* >( slotObject ); break; } case Call: @@ -218,7 +160,7 @@ public: typedef QtPrivate::Functor< Function, N > FuncType; FuncType::template call< Args, R >( - invokable->m_function, object, args ); + static_cast< Invokable* >( slotObject )->m_function, object, args ); break; }