VirtualBox

Ignore:
Timestamp:
Feb 5, 2020 7:14:36 PM (5 years ago)
Author:
vboxsync
Message:

FE/Qt: bugref:9653: Splitting UIThreadPool and UITask into separate files to break few dependencies.

Location:
trunk/src/VBox/Frontends/VirtualBox
Files:
6 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk

    r82995 r82998  
    825825        src/globals/UIProgressEventHandler.h \
    826826        src/globals/UIShortcutPool.h \
     827        src/globals/UITask.h \
    827828        src/globals/UIThreadPool.h \
    828829        src/globals/UITextTable.h \
     
    13241325        src/globals/UIShortcutPool.cpp \
    13251326        src/globals/UITextTable.cpp \
     1327        src/globals/UITask.cpp \
    13261328        src/globals/UIThreadPool.cpp \
    13271329        src/globals/UIVersion.cpp \
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UITask.cpp

    r82974 r82998  
    11/* $Id$ */
    22/** @file
    3  * VBox Qt GUI - UIThreadPool and UITask classes implementation.
     3 * VBox Qt GUI - UITask class implementation.
    44 */
    55
     
    1616 */
    1717
    18 /* Qt includes: */
    19 #include <QThread>
    20 
    2118/* GUI includes: */
    22 #include "COMDefs.h"
    23 #include "UIDefs.h"
    24 #include "UIThreadPool.h"
    25 
    26 /* Other VBox includes: */
    27 #include <iprt/assert.h>
    28 
    29 
    30 /** QThread extension used as worker-thread.
    31   * Capable of executing COM-related tasks. */
    32 class UIThreadWorker : public QThread
    33 {
    34     Q_OBJECT;
    35 
    36 signals:
    37 
    38     /** Notifies listeners about @a pWorker finished. */
    39     void sigFinished(UIThreadWorker *pWorker);
    40 
    41 public:
    42 
    43     /** Constructs worker-thread for parent worker-thread @a pPool.
    44       * @param  iIndex  Brings worker-thread index within the worker-thread pool registry. */
    45     UIThreadWorker(UIThreadPool *pPool, int iIndex);
    46 
    47     /** Returns worker-thread index within the worker-thread pool registry. */
    48     int index() const { return m_iIndex; }
    49 
    50     /** Disables sigFinished signal, for optimizing worker-thread pool termination. */
    51     void setNoFinishedSignal() { m_fNoFinishedSignal = true; }
    52 
    53 private:
    54 
    55     /** Contains the worker-thread body. */
    56     void run();
    57 
    58     /** Holds the worker-thread pool reference. */
    59     UIThreadPool *m_pPool;
    60 
    61     /** Holds the worker-thread index within the worker-thread pool registry. */
    62     int m_iIndex;
    63 
    64     /** Holds whether sigFinished signal should be emitted or not. */
    65     bool m_fNoFinishedSignal;
    66 };
    67 
    68 
    69 /*********************************************************************************************************************************
    70 *   Class UIThreadPool implementation.                                                                                           *
    71 *********************************************************************************************************************************/
    72 
    73 UIThreadPool::UIThreadPool(ulong cMaxWorkers /* = 3 */, ulong cMsWorkerIdleTimeout /* = 5000 */)
    74     : m_cMsIdleTimeout(cMsWorkerIdleTimeout)
    75     , m_workers(cMaxWorkers)
    76     , m_cWorkers(0)
    77     , m_cIdleWorkers(0)
    78     , m_fTerminating(false)
    79 {
    80 }
    81 
    82 UIThreadPool::~UIThreadPool()
    83 {
    84     /* Set termination status: */
    85     setTerminating();
    86 
    87     /* Lock initially: */
    88     m_everythingLocker.lock();
    89 
    90     /* Cleanup all the workers: */
    91     for (int idxWorker = 0; idxWorker < m_workers.size(); ++idxWorker)
    92     {
    93         /* Acquire the worker: */
    94         UIThreadWorker *pWorker = m_workers.at(idxWorker);
    95         /* Remove it from the registry: */
    96         m_workers[idxWorker] = 0;
    97 
    98         /* Clean up the worker, if there was one: */
    99         if (pWorker)
    100         {
    101             /* Decrease the number of workers: */
    102             --m_cWorkers;
    103             /* Unlock temporary to let the worker finish: */
    104             m_everythingLocker.unlock();
    105             /* Wait for the worker to finish: */
    106             pWorker->wait();
    107             /* Lock again: */
    108             m_everythingLocker.lock();
    109             /* Delete the worker finally: */
    110             delete pWorker;
    111         }
    112     }
    113 
    114     /* Cleanup all the tasks: */
    115     qDeleteAll(m_pendingTasks);
    116     qDeleteAll(m_executingTasks);
    117     m_pendingTasks.clear();
    118     m_executingTasks.clear();
    119 
    120     /* Unlock finally: */
    121     m_everythingLocker.unlock();
    122 }
    123 
    124 bool UIThreadPool::isTerminating() const
    125 {
    126     /* Lock initially: */
    127     m_everythingLocker.lock();
    128 
    129     /* Acquire termination-flag: */
    130     bool fTerminating = m_fTerminating;
    131 
    132     /* Unlock finally: */
    133     m_everythingLocker.unlock();
    134 
    135     /* Return termination-flag: */
    136     return fTerminating;
    137 }
    138 
    139 void UIThreadPool::setTerminating()
    140 {
    141     /* Lock initially: */
    142     m_everythingLocker.lock();
    143 
    144     /* Assign termination-flag: */
    145     m_fTerminating = true;
    146 
    147     /* Tell all threads to NOT queue any termination signals: */
    148     for (int idxWorker = 0; idxWorker < m_workers.size(); ++idxWorker)
    149     {
    150         UIThreadWorker *pWorker = m_workers.at(idxWorker);
    151         if (pWorker)
    152             pWorker->setNoFinishedSignal();
    153     }
    154 
    155     /* Wake up all idle worker threads: */
    156     m_taskCondition.wakeAll();
    157 
    158     /* Unlock finally: */
    159     m_everythingLocker.unlock();
    160 }
    161 
    162 void UIThreadPool::enqueueTask(UITask *pTask)
    163 {
    164     /* Do nothing if terminating: */
    165     AssertReturnVoid(!isTerminating());
    166 
    167     /* Prepare task: */
    168     connect(pTask, &UITask::sigComplete,
    169             this, &UIThreadPool::sltHandleTaskComplete, Qt::QueuedConnection);
    170 
    171     /* Lock initially: */
    172     m_everythingLocker.lock();
    173 
    174     /* Put the task into the queue: */
    175     m_pendingTasks.enqueue(pTask);
    176 
    177     /* Wake up an idle worker if we got one: */
    178     if (m_cIdleWorkers > 0)
    179     {
    180         m_taskCondition.wakeOne();
    181     }
    182     /* No idle worker threads, should we create a new one? */
    183     else if (m_cWorkers < m_workers.size())
    184     {
    185         /* Find free slot: */
    186         int idxFirstUnused = m_workers.size();
    187         while (idxFirstUnused-- > 0)
    188             if (m_workers.at(idxFirstUnused) == 0)
    189             {
    190                 /* Prepare the new worker: */
    191                 UIThreadWorker *pWorker = new UIThreadWorker(this, idxFirstUnused);
    192                 connect(pWorker, &UIThreadWorker::sigFinished,
    193                         this, &UIThreadPool::sltHandleWorkerFinished, Qt::QueuedConnection);
    194                 m_workers[idxFirstUnused] = pWorker;
    195                 ++m_cWorkers;
    196 
    197                 /* And start it: */
    198                 pWorker->start();
    199                 break;
    200             }
    201     }
    202     /* else: wait for some worker to complete
    203      * whatever it's busy with and jump to it. */
    204 
    205     /* Unlock finally: */
    206     m_everythingLocker.unlock();
    207 }
    208 
    209 UITask *UIThreadPool::dequeueTask(UIThreadWorker *pWorker)
    210 {
    211     /* Lock initially: */
    212     m_everythingLocker.lock();
    213 
    214     /* Dequeue a task, watching out for terminations.
    215      * For optimal efficiency in enqueueTask() we keep count of idle threads.
    216      * If the wait times out, we'll return 0 and terminate the thread. */
    217     bool fIdleTimedOut = false;
    218     while (!m_fTerminating)
    219     {
    220         /* Make sure that worker has proper index: */
    221         Assert(m_workers.at(pWorker->index()) == pWorker);
    222 
    223         /* Dequeue task if there is one: */
    224         if (!m_pendingTasks.isEmpty())
    225         {
    226             UITask *pTask = m_pendingTasks.dequeue();
    227             if (pTask)
    228             {
    229                 /* Put into the set of executing tasks: */
    230                 m_executingTasks << pTask;
    231 
    232                 /* Unlock finally: */
    233                 m_everythingLocker.unlock();
    234 
    235                 /* Return dequeued task: */
    236                 return pTask;
    237             }
    238         }
    239 
    240         /* If we timed out already, then quit the worker thread. To prevent a
    241          * race between enqueueTask and the queue removal of the thread from
    242          * the workers vector, we remove it here already. (This does not apply
    243          * to the termination scenario.) */
    244         if (fIdleTimedOut)
    245         {
    246             m_workers[pWorker->index()] = 0;
    247             --m_cWorkers;
    248             break;
    249         }
    250 
    251         /* Wait for a task or timeout: */
    252         ++m_cIdleWorkers;
    253         fIdleTimedOut = !m_taskCondition.wait(&m_everythingLocker, m_cMsIdleTimeout);
    254         --m_cIdleWorkers;
    255     }
    256 
    257     /* Unlock finally: */
    258     m_everythingLocker.unlock();
    259 
    260     /* Return 0 by default: */
    261     return 0;
    262 }
    263 
    264 void UIThreadPool::sltHandleTaskComplete(UITask *pTask)
    265 {
    266     /* Skip on termination: */
    267     if (isTerminating())
    268         return;
    269 
    270     /* Notify listeners: */
    271     emit sigTaskComplete(pTask);
    272 
    273     /* Lock initially: */
    274     m_everythingLocker.lock();
    275 
    276     /* Delete task finally: */
    277     if (   !m_executingTasks.contains(pTask)
    278         || !m_executingTasks.remove(pTask))
    279         AssertMsgFailed(("Unable to find or remove complete task!"));
    280     delete pTask;
    281 
    282     /* Unlock finally: */
    283     m_everythingLocker.unlock();
    284 }
    285 
    286 void UIThreadPool::sltHandleWorkerFinished(UIThreadWorker *pWorker)
    287 {
    288     /* Wait for the thread to finish completely, then delete the thread
    289      * object. We have already removed the thread from the workers vector.
    290      * Note! We don't want to use 'this' here, in case it's invalid. */
    291     pWorker->wait();
    292     delete pWorker;
    293 }
     19#include "UITask.h"
    29420
    29521void UITask::start()
     
    30026    emit sigComplete(this);
    30127}
    302 
    303 
    304 /*********************************************************************************************************************************
    305 *   Class UIThreadWorker implementation.                                                                                         *
    306 *********************************************************************************************************************************/
    307 
    308 UIThreadWorker::UIThreadWorker(UIThreadPool *pPool, int iIndex)
    309     : m_pPool(pPool)
    310     , m_iIndex(iIndex)
    311     , m_fNoFinishedSignal(false)
    312 {
    313 }
    314 
    315 void UIThreadWorker::run()
    316 {
    317     /* Initialize COM: */
    318     COMBase::InitializeCOM(false);
    319 
    320     /* Try get a task from the pool queue: */
    321     while (UITask *pTask = m_pPool->dequeueTask(this))
    322     {
    323         /* Process the task if we are not terminating.
    324          * Please take into account tasks are cleared by the UIThreadPool
    325          * after all listeners notified about task is complete and handled it. */
    326         if (!m_pPool->isTerminating())
    327             pTask->start();
    328     }
    329 
    330     /* Cleanup COM: */
    331     COMBase::CleanupCOM();
    332 
    333     /* Queue a signal for the pool to do thread cleanup, unless the pool is
    334        already terminating and doesn't need the signal. */
    335     if (!m_fNoFinishedSignal)
    336         emit sigFinished(this);
    337 }
    338 
    339 
    340 #include "UIThreadPool.moc"
    341 
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UITask.h

    r82974 r82998  
    11/* $Id$ */
    22/** @file
    3  * VBox Qt GUI - UIThreadPool and UITask classes declaration.
     3 * VBox Qt GUI - UITask class declaration.
    44 */
    55
     
    1616 */
    1717
    18 #ifndef FEQT_INCLUDED_SRC_globals_UIThreadPool_h
    19 #define FEQT_INCLUDED_SRC_globals_UIThreadPool_h
     18#ifndef FEQT_INCLUDED_SRC_globals_UITask_h
     19#define FEQT_INCLUDED_SRC_globals_UITask_h
    2020#ifndef RT_WITHOUT_PRAGMA_ONCE
    2121# pragma once
     
    2323
    2424/* Qt includes: */
    25 #include <QMutex>
    2625#include <QObject>
    27 #include <QQueue>
    28 #include <QSet>
    29 #include <QVariant>
    30 #include <QVector>
    31 #include <QWaitCondition>
    3226
    3327/* GUI includes: */
    3428#include "UILibraryDefs.h"
    3529
    36 /* Forward declarations: */
    37 class UITask;
    38 class UIThreadWorker;
    39 
    40 
    41 /** QObject extension used as worker-thread pool.
    42   * Schedules COM-related GUI tasks to multiple worker-threads. */
    43 class SHARED_LIBRARY_STUFF UIThreadPool : public QObject
    44 {
    45     Q_OBJECT;
    46 
    47 signals:
    48 
    49     /** Notifies listeners about @a pTask complete. */
    50     void sigTaskComplete(UITask *pTask);
    51 
    52 public:
    53 
    54     /** Constructs worker-thread pool.
    55       * @param  cMaxWorkers           Brings the maximum amount of worker-threads.
    56       * @param  cMsWorkerIdleTimeout  Brings the maximum amount of time (in ms) which
    57       *                               pool will wait for the worker-thread on cleanup. */
    58     UIThreadPool(ulong cMaxWorkers = 3, ulong cMsWorkerIdleTimeout = 5000);
    59     /** Destructs worker-thread pool. */
    60     ~UIThreadPool();
    61 
    62     /** Returns whether the 'termination sequence' is started. */
    63     bool isTerminating() const;
    64     /** Defines that the 'termination sequence' is started. */
    65     void setTerminating();
    66 
    67     /** Enqueues @a pTask into the task-queue. */
    68     void enqueueTask(UITask *pTask);
    69     /** Returns dequeued top-most task from the task-queue. */
    70     UITask *dequeueTask(UIThreadWorker *pWorker);
    71 
    72 private slots:
    73 
    74     /** Handles @a pTask complete signal. */
    75     void sltHandleTaskComplete(UITask *pTask);
    76 
    77     /** Handles @a pWorker finished signal. */
    78     void sltHandleWorkerFinished(UIThreadWorker *pWorker);
    79 
    80 private:
    81 
    82     /** @name Worker-thread stuff.
    83      * @{ */
    84         /** Holds the maximum amount of time (in ms) which
    85           * pool will wait for the worker-thread on cleanup. */
    86         const ulong               m_cMsIdleTimeout;
    87         /** Holds the vector of worker-threads. */
    88         QVector<UIThreadWorker*>  m_workers;
    89         /** Holds the number of worker-threads.
    90           * @remarks We cannot use the vector size since it may contain 0 pointers. */
    91         int                       m_cWorkers;
    92         /** Holds the number of idle worker-threads. */
    93         int                       m_cIdleWorkers;
    94         /** Holds whether the 'termination sequence' is started
    95           * and all worker-threads should terminate ASAP. */
    96         bool                      m_fTerminating;
    97     /** @} */
    98 
    99     /** @name Task stuff
    100      * @{ */
    101         /** Holds the queue of pending tasks. */
    102         QQueue<UITask*>  m_pendingTasks;
    103         /** Holds the set of executing tasks. */
    104         QSet<UITask*>    m_executingTasks;
    105         /** Holds the condition variable that gets signalled when
    106           * queuing a new task and there are idle worker threads around.
    107           * @remarks Idle threads sits in dequeueTask waiting for this.
    108           *          Thus on thermination, setTerminating() will send a
    109           *          broadcast signal to wake up all workers (after
    110           *          setting m_fTerminating of course). */
    111         QWaitCondition   m_taskCondition;
    112     /** @} */
    113 
    114     /** Holds the guard mutex object protecting
    115       * all the inter-thread variables. */
    116     mutable QMutex m_everythingLocker;
    117 };
    118 
    119 
    12030/** QObject extension used as worker-thread task interface.
    121   * Describes task to be executed by the UIThreadWorker object. */
     31  * Describes task to be handled by the UIThreadPool object. */
    12232class SHARED_LIBRARY_STUFF UITask : public QObject
    12333{
     
    15565
    15666    /** Holds the type of the task. */
    157     const UITask::Type m_enmType;
     67    const UITask::Type  m_enmType;
    15868};
    15969
    160 
    161 #endif /* !FEQT_INCLUDED_SRC_globals_UIThreadPool_h */
    162 
     70#endif /* !FEQT_INCLUDED_SRC_globals_UITask_h */
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UIThreadPool.cpp

    r82968 r82998  
    11/* $Id$ */
    22/** @file
    3  * VBox Qt GUI - UIThreadPool and UITask classes implementation.
     3 * VBox Qt GUI - UIThreadPool class implementation.
    44 */
    55
     
    2222#include "COMDefs.h"
    2323#include "UIDefs.h"
     24#include "UITask.h"
    2425#include "UIThreadPool.h"
    2526
     
    6061
    6162    /** Holds the worker-thread index within the worker-thread pool registry. */
    62     int m_iIndex;
     63    int  m_iIndex;
    6364
    6465    /** Holds whether sigFinished signal should be emitted or not. */
    65     bool m_fNoFinishedSignal;
     66    bool  m_fNoFinishedSignal;
    6667};
    6768
     
    293294}
    294295
    295 void UITask::start()
    296 {
    297     /* Run task: */
    298     run();
    299     /* Notify listeners: */
    300     emit sigComplete(this);
    301 }
    302 
    303296
    304297/*********************************************************************************************************************************
     
    339332
    340333#include "UIThreadPool.moc"
    341 
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UIThreadPool.h

    r82968 r82998  
    11/* $Id$ */
    22/** @file
    3  * VBox Qt GUI - UIThreadPool and UITask classes declaration.
     3 * VBox Qt GUI - UIThreadPool class declaration.
    44 */
    55
     
    2727#include <QQueue>
    2828#include <QSet>
    29 #include <QVariant>
    3029#include <QVector>
    3130#include <QWaitCondition>
     
    3736class UITask;
    3837class UIThreadWorker;
    39 
    4038
    4139/** QObject extension used as worker-thread pool.
     
    5856    UIThreadPool(ulong cMaxWorkers = 3, ulong cMsWorkerIdleTimeout = 5000);
    5957    /** Destructs worker-thread pool. */
    60     ~UIThreadPool();
     58    virtual ~UIThreadPool() /* override */;
    6159
    6260    /** Returns whether the 'termination sequence' is started. */
     
    114112    /** Holds the guard mutex object protecting
    115113      * all the inter-thread variables. */
    116     mutable QMutex m_everythingLocker;
     114    mutable QMutex  m_everythingLocker;
    117115};
    118116
    119 
    120 /** QObject extension used as worker-thread task interface.
    121   * Describes task to be executed by the UIThreadWorker object. */
    122 class SHARED_LIBRARY_STUFF UITask : public QObject
    123 {
    124     Q_OBJECT;
    125 
    126 signals:
    127 
    128     /** Notifies listeners about @a pTask complete. */
    129     void sigComplete(UITask *pTask);
    130 
    131 public:
    132 
    133     /** Task types. */
    134     enum Type
    135     {
    136         Type_MediumEnumeration = 1,
    137         Type_DetailsPopulation = 2,
    138     };
    139 
    140     /** Constructs the task of passed @a enmType. */
    141     UITask(UITask::Type enmType) : m_enmType(enmType) {}
    142 
    143     /** Returns the type of the task. */
    144     UITask::Type type() const { return m_enmType; }
    145 
    146     /** Starts the task. */
    147     void start();
    148 
    149 protected:
    150 
    151     /** Contains the abstract task body. */
    152     virtual void run() = 0;
    153 
    154 private:
    155 
    156     /** Holds the type of the task. */
    157     const UITask::Type m_enmType;
    158 };
    159 
    160 
    161117#endif /* !FEQT_INCLUDED_SRC_globals_UIThreadPool_h */
    162 
  • trunk/src/VBox/Frontends/VirtualBox/src/manager/details/UIDetailsElements.cpp

    r82968 r82998  
    1818/* Qt includes: */
    1919#include <QDir>
     20#include <QGraphicsLinearLayout>
    2021#include <QTimer>
    21 #include <QGraphicsLinearLayout>
    2222
    2323/* GUI includes: */
     24#include "UICommon.h"
     25#include "UIConverter.h"
    2426#include "UIDetailsElements.h"
    2527#include "UIDetailsGenerator.h"
    2628#include "UIDetailsModel.h"
     29#include "UIErrorString.h"
     30#include "UIGraphicsRotatorButton.h"
     31#include "UIGraphicsTextPane.h"
     32#include "UIIconPool.h"
    2733#include "UIMachinePreview.h"
    28 #include "UIGraphicsRotatorButton.h"
    29 #include "UICommon.h"
    30 #include "UIIconPool.h"
    31 #include "UIConverter.h"
    32 #include "UIGraphicsTextPane.h"
    33 #include "UIErrorString.h"
     34#include "UIThreadPool.h"
    3435
    3536/* COM includes: */
    3637#include "COMEnums.h"
     38#include "CAudioAdapter.h"
    3739#include "CMachine.h"
     40#include "CMedium.h"
     41#include "CMediumAttachment.h"
     42#include "CNetworkAdapter.h"
     43#include "CRecordingScreenSettings.h"
     44#include "CRecordingSettings.h"
     45#include "CSerialPort.h"
     46#include "CSharedFolder.h"
     47#include "CStorageController.h"
    3848#include "CSystemProperties.h"
     49#include "CUSBController.h"
     50#include "CUSBDeviceFilter.h"
     51#include "CUSBDeviceFilters.h"
    3952#include "CVRDEServer.h"
    40 #include "CStorageController.h"
    41 #include "CMediumAttachment.h"
    42 #include "CAudioAdapter.h"
    43 #include "CRecordingSettings.h"
    44 #include "CRecordingScreenSettings.h"
    45 #include "CNetworkAdapter.h"
    46 #include "CSerialPort.h"
    47 #include "CUSBController.h"
    48 #include "CUSBDeviceFilters.h"
    49 #include "CUSBDeviceFilter.h"
    50 #include "CSharedFolder.h"
    51 #include "CMedium.h"
    5253
    5354UIDetailsUpdateTask::UIDetailsUpdateTask(const CMachine &machine)
  • trunk/src/VBox/Frontends/VirtualBox/src/manager/details/UIDetailsElements.h

    r82968 r82998  
    2323
    2424/* GUI includes: */
    25 #include "UIThreadPool.h"
    2625#include "UIDetailsElement.h"
     26#include "UITask.h"
    2727
    2828/* Forward declarations: */
  • trunk/src/VBox/Frontends/VirtualBox/src/medium/UIMediumEnumerator.cpp

    r82968 r82998  
    2323#include "UIMediumEnumerator.h"
    2424#include "UIMessageCenter.h"
     25#include "UITask.h"
    2526#include "UIThreadPool.h"
    2627#include "UIVirtualBoxEventHandler.h"
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette