<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Mar 20, 2017 at 2:01 PM, Frediano Ziglio <span dir="ltr"><<a href="mailto:fziglio@redhat.com" target="_blank">fziglio@redhat.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div class="gmail-HOEnZb"><div class="gmail-h5">><br>
> Create rendering thread upon device start and terminate it upon<br>
> stop. The dedicated thread is normally pending for display commands<br>
> to be sent to the host. Currently only single NULL (termination)<br>
> command is placed to the ring where the thread consumes events from.<br>
><br>
> Signed-off-by: Javier Celaya <<a href="mailto:javier.celaya@flexvdi.com">javier.celaya@flexvdi.com</a>><br>
> Signed-off-by: Yuri Benditovich <<a href="mailto:yuri.benditovich@daynix.com">yuri.benditovich@daynix.com</a>><br>
> ---<br>
>  qxldod/QxlDod.cpp | 114<br>
>  ++++++++++++++++++++++++++++++<wbr>++++++++++++++++++++++++<br>
>  qxldod/QxlDod.h   |  16 ++++++++<br>
>  2 files changed, 130 insertions(+)<br>
><br>
> diff --git a/qxldod/QxlDod.cpp b/qxldod/QxlDod.cpp<br>
> index 9175300..b952bf9 100755<br>
> --- a/qxldod/QxlDod.cpp<br>
> +++ b/qxldod/QxlDod.cpp<br>
> @@ -3062,6 +3062,7 @@ QxlDevice::QxlDevice(_In_ QxlDod* pQxlDod)<br>
>      m_CustomMode = 0;<br>
>      m_FreeOutputs = 0;<br>
>      m_Pending = 0;<br>
> +    m_PresentThread = NULL;<br>
>  }<br>
><br>
>  QxlDevice::~QxlDevice(void)<br>
> @@ -3441,6 +3442,29 @@ NTSTATUS QxlDevice::HWInit(PCM_<wbr>RESOURCE_LIST pResList,<br>
> DXGK_DISPLAY_INFORMATION*<br>
>      return QxlInit(pDispInfo);<br>
>  }<br>
><br>
> +NTSTATUS QxlDevice::StartPresentThread(<wbr>)<br>
> +{<br>
> +    PAGED_CODE();<br>
> +    OBJECT_ATTRIBUTES ObjectAttributes;<br>
> +    NTSTATUS Status;<br>
> +<br>
> +    KeClearEvent(&m_<wbr>PresentThreadReadyEvent);<br>
> +<br>
> +    InitializeObjectAttributes(&<wbr>ObjectAttributes, NULL, OBJ_KERNEL_HANDLE,<br>
> NULL, NULL);<br>
> +    Status = PsCreateSystemThread(<br>
> +        &m_PresentThread,<br>
> +        THREAD_ALL_ACCESS,<br>
> +        &ObjectAttributes,<br>
> +        NULL,<br>
> +        NULL,<br>
> +        PresentThreadRoutineWrapper,<br>
> +        this);<br>
> +<br>
> +    WaitForObject(&m_<wbr>PresentThreadReadyEvent, NULL);<br>
> +<br>
<br>
</div></div>Why we need to wait here? Same above, no much need to clear the event.<br>
<div><div class="gmail-h5"><br></div></div></blockquote><div>Wait is not mandatory - it is here to have predictable timing and ensure the thread is ready before first 'Present' command.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div class="gmail-h5">
> +    return Status;<br>
> +}<br>
> +<br>
>  NTSTATUS QxlDevice::QxlInit(DXGK_<wbr>DISPLAY_INFORMATION* pDispInfo)<br>
>  {<br>
>      PAGED_CODE();<br>
> @@ -3467,12 +3491,17 @@ NTSTATUS QxlDevice::QxlInit(DXGK_<wbr>DISPLAY_INFORMATION*<br>
> pDispInfo)<br>
>      InitDeviceMemoryResources();<br>
>      InitMonitorConfig();<br>
>      Status = AcquireDisplayInfo(*(<wbr>pDispInfo));<br>
> +    if (NT_SUCCESS(Status))<br>
> +    {<br>
> +        Status = StartPresentThread();<br>
> +    }<br>
>      return Status;<br>
>  }<br>
><br>
>  void QxlDevice::QxlClose()<br>
>  {<br>
>      PAGED_CODE();<br>
> +    StopPresentThread();<br>
>      DestroyMemSlots();<br>
>  }<br>
><br>
> @@ -3609,6 +3638,12 @@ BOOL QxlDevice::CreateEvents()<br>
>      KeInitializeEvent(&m_<wbr>IoCmdEvent,<br>
>                        SynchronizationEvent,<br>
>                        FALSE);<br>
> +    KeInitializeEvent(&m_<wbr>PresentEvent,<br>
> +                      SynchronizationEvent,<br>
> +                      FALSE);<br>
> +    KeInitializeEvent(&m_<wbr>PresentThreadReadyEvent,<br>
> +                      SynchronizationEvent,<br>
> +                      FALSE);<br>
>      KeInitializeMutex(&m_MemLock,<wbr>1);<br>
>      KeInitializeMutex(&m_CmdLock,<wbr>1);<br>
>      KeInitializeMutex(&m_IoLock,1)<wbr>;<br>
> @@ -3625,6 +3660,7 @@ BOOL QxlDevice::CreateRings()<br>
>      m_CommandRing = &(m_RamHdr->cmd_ring);<br>
>      m_CursorRing = &(m_RamHdr->cursor_ring);<br>
>      m_ReleaseRing = &(m_RamHdr->release_ring);<br>
> +    SPICE_RING_INIT(m_PresentRing)<wbr>;<br>
>      DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));<br>
>      return TRUE;<br>
>  }<br>
> @@ -4907,6 +4943,7 @@ UINT SpiceFromPixelFormat(<wbr>D3DDDIFORMAT Format)<br>
><br>
>  NTSTATUS HwDeviceInterface::<wbr>AcquireDisplayInfo(DXGK_<wbr>DISPLAY_INFORMATION&<br>
>  DispInfo)<br>
>  {<br>
> +    PAGED_CODE();<br>
>      NTSTATUS Status = STATUS_SUCCESS;<br>
>      if (GetId() == 0)<br>
>      {<br>
> @@ -4996,3 +5033,80 @@ QXL_NON_PAGED VOID QxlDod::VsyncTimerProcGate(_<wbr>In_<br>
> _KDPC *dpc, _In_ PVOID contex<br>
>      QxlDod* pQxl = reinterpret_cast<QxlDod*>(<wbr>context);<br>
>      pQxl->VsyncTimerProc();<br>
>  }<br>
> +<br>
> +void QxlDevice::StopPresentThread()<br>
> +{<br>
> +    PAGED_CODE();<br>
> +    PVOID pDispatcherObject;<br>
> +    if (m_PresentThread)<br>
> +    {<br>
> +        DbgPrint(TRACE_LEVEL_<wbr>INFORMATION, ("---> %s\n", __FUNCTION__));<br>
> +        NTSTATUS Status = ObReferenceObjectByHandle(<br>
> +            m_PresentThread, 0, NULL, KernelMode, &pDispatcherObject, NULL);<br>
> +        if (NT_SUCCESS(Status))<br>
> +        {<br>
> +            PostToWorkerThread(NULL);<br>
<br>
</div></div>In the unluckily event that ObReferenceObjectByHandle failed would<br>
be better to do this call anyway, so we have a chance the thread<br>
will be destroyed before system potentially free from memory<br>
the thread code and data.<br>
<div><div class="gmail-h5"><br>
> +            WaitForObject(<wbr>pDispatcherObject, NULL);<br>
> +            ObDereferenceObject(<wbr>pDispatcherObject);<br>
> +        }<br>
> +        ZwClose(m_PresentThread);<br>
> +        m_PresentThread = NULL;<br>
> +        DbgPrint(TRACE_LEVEL_<wbr>INFORMATION, ("<--- %s\n", __FUNCTION__));<br>
> +    }<br>
> +}<br>
> +<br>
> +void QxlDevice::<wbr>PresentThreadRoutine()<br>
> +{<br>
> +    PAGED_CODE();<br>
> +    int wait;<br>
> +    int notify;<br>
> +    QXLDrawable** drawables;<br>
> +<br>
> +    DbgPrint(TRACE_LEVEL_<wbr>INFORMATION, ("--->%s\n", __FUNCTION__));<br>
> +<br>
> +    KeSetEvent(&m_<wbr>PresentThreadReadyEvent, 0, FALSE);<br>
> +<br>
> +    while (1)<br>
> +    {<br>
> +        // Pop a drawables list from the ring<br>
> +        // No need for a mutex, only one consumer thread<br>
> +        SPICE_RING_CONS_WAIT(m_<wbr>PresentRing, wait);<br>
> +        while (wait) {<br>
> +            WaitForObject(&m_PresentEvent, NULL);<br>
> +            SPICE_RING_CONS_WAIT(m_<wbr>PresentRing, wait);<br>
> +        }<br>
> +        drawables = *SPICE_RING_CONS_ITEM(m_<wbr>PresentRing);<br>
> +        SPICE_RING_POP(m_PresentRing, notify);<br>
> +        if (notify) {<br>
> +            KeSetEvent(&m_<wbr>PresentThreadReadyEvent, 0, FALSE);<br>
> +        }<br>
> +<br>
> +        if (drawables) {<br>
> +            for (UINT i = 0; drawables[i]; ++i)<br>
> +                PushDrawable(drawables[i]);<br>
> +            delete[] reinterpret_cast<BYTE*>(<wbr>drawables);<br>
<br>
</div></div>why all these reinterpret_cast ?<br>
Just<br>
<br>
  delete[] drawables;<br>
<br>
is enough (obviously allocation should the changed too).<br>
<div><div class="gmail-h5"><br>
> +        }<br>
> +        else {<br>
> +            DbgPrint(TRACE_LEVEL_WARNING, ("%s is being terminated\n",<br>
> __FUNCTION__));<br>
> +            break;<br>
> +        }<br>
> +    }<br>
> +}<br>
> +<br>
> +void QxlDevice::PostToWorkerThread(<wbr>QXLDrawable** drawables)<br>
> +{<br>
> +    PAGED_CODE();<br>
> +    // Push drawables into PresentRing and notify worker thread<br>
> +    int notify, wait;<br>
> +    SPICE_RING_PROD_WAIT(m_<wbr>PresentRing, wait);<br>
> +    while (wait) {<br>
> +        WaitForObject(&m_<wbr>PresentThreadReadyEvent, NULL);<br>
> +        SPICE_RING_PROD_WAIT(m_<wbr>PresentRing, wait);<br>
> +    }<br>
> +    *SPICE_RING_PROD_ITEM(m_<wbr>PresentRing) = drawables;<br>
> +    SPICE_RING_PUSH(m_PresentRing, notify);<br>
> +    if (notify) {<br>
> +        KeSetEvent(&m_PresentEvent, 0, FALSE);<br>
> +    }<br>
> +    DbgPrint(TRACE_LEVEL_<wbr>INFORMATION, ("<--- %s\n", __FUNCTION__));<br>
> +}<br>
> diff --git a/qxldod/QxlDod.h b/qxldod/QxlDod.h<br>
> index 9cfb6de..4a62680 100755<br>
> --- a/qxldod/QxlDod.h<br>
> +++ b/qxldod/QxlDod.h<br>
> @@ -456,6 +456,10 @@ typedef struct DpcCbContext {<br>
>  #define MAX(x, y) (((x) >= (y)) ? (x) : (y))<br>
>  #define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))<br>
><br>
> +#include "start-packed.h"<br>
> +SPICE_RING_DECLARE(<wbr>QXLPresentOnlyRing, QXLDrawable**, 1024);<br>
> +#include "end-packed.h"<br>
> +<br>
<br>
</div></div>Not a regression, however this structure cannot be byte-packed.<br>
This would cause potentially problems like 255+1 == 0.<br>
<div class="gmail-HOEnZb"><div class="gmail-h5"><br>
</div></div></blockquote><div>I do not see how this can cause problem.</div><div>Packing at byte boundary is not needed here, but the alternative is (ugly) to use #define SPICE_ATTR_PACKED before declaration and #undef SPICE_ATTR_PACKED after.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div class="gmail-HOEnZb"><div class="gmail-h5">>  class QxlDevice  :<br>
>      public HwDeviceInterface<br>
>  {<br>
> @@ -559,6 +563,13 @@ private:<br>
>      NTSTATUS UpdateChildStatus(BOOLEAN connect);<br>
>      NTSTATUS SetCustomDisplay(<wbr>QXLEscapeSetCustomDisplay* custom_display);<br>
>      void SetMonitorConfig(QXLHead* monitor_config);<br>
> +    NTSTATUS StartPresentThread();<br>
> +    void StopPresentThread();<br>
> +    void PresentThreadRoutine();<br>
> +    static void PresentThreadRoutineWrapper(<wbr>HANDLE dev) {<br>
> +        ((QxlDevice *)dev)->PresentThreadRoutine()<wbr>;<br>
> +    }<br>
> +    void PostToWorkerThread(<wbr>QXLDrawable** drawables);<br>
><br>
>      static LONG GetMaxSourceMappingHeight(<wbr>RECT* DirtyRects, ULONG<br>
>      NumDirtyRects);<br>
><br>
> @@ -594,6 +605,8 @@ private:<br>
>      KEVENT m_DisplayEvent;<br>
>      KEVENT m_CursorEvent;<br>
>      KEVENT m_IoCmdEvent;<br>
> +    KEVENT m_PresentEvent;<br>
> +    KEVENT m_PresentThreadReadyEvent;<br>
><br>
>      PUCHAR m_LogPort;<br>
>      PUCHAR m_LogBuf;<br>
> @@ -609,6 +622,9 @@ private:<br>
><br>
>      QXLMonitorsConfig* m_monitor_config;<br>
>      QXLPHYSICAL* m_monitor_config_pa;<br>
> +<br>
> +    QXLPresentOnlyRing m_PresentRing[1];<br>
> +    HANDLE m_PresentThread;<br>
>  };<br>
><br>
>  class QxlDod {<br>
<br>
</div></div><span class="gmail-HOEnZb"><font color="#888888">Frediano<br>
</font></span></blockquote></div><br></div></div>