diff options
Diffstat (limited to 'indra/llwindow')
| -rw-r--r-- | indra/llwindow/llwindowwin32.cpp | 186 | 
1 files changed, 92 insertions, 94 deletions
| diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 1cac6ffe08..4a4dab712b 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -350,10 +350,14 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool      LLWindowWin32Thread();      void run() override; -    void close() override; -    // closes queue, wakes thread, waits until thread closes -    void wakeAndDestroy(); +    // Detroys handles and window +    // Either post to or call from window thread +    void destroyWindow(); + +    // Closes queue, wakes thread, waits until thread closes. +    // Call from main thread +    bool wakeAndDestroy();      void glReady()      { @@ -410,6 +414,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool      // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18      bool mGLReady = false;      bool mGotGLBuffer = false; +    LLAtomicBool mDeleteOnExit = false;  }; @@ -853,6 +858,7 @@ LLWindowWin32::~LLWindowWin32()      }      delete mDragDrop; +    mDragDrop = NULL;      delete [] mWindowTitle;      mWindowTitle = NULL; @@ -864,6 +870,7 @@ LLWindowWin32::~LLWindowWin32()      mWindowClassName = NULL;      delete mWindowThread; +    mWindowThread = NULL;  }  void LLWindowWin32::show() @@ -982,7 +989,11 @@ void LLWindowWin32::close()      mhDC = NULL;      mWindowHandle = NULL; -    mWindowThread->wakeAndDestroy(); +    if (mWindowThread->wakeAndDestroy()) +    { +        // thread will delete itselfs once done +        mWindowThread = NULL; +    }  }  bool LLWindowWin32::isValid() @@ -3104,10 +3115,14 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_          break;          }      } -    else +    else // (NULL == window_imp)      { -        // (NULL == window_imp)          LL_DEBUGS("Window") << "No window implementation to handle message with, message code: " << U32(u_msg) << LL_ENDL; +        if (u_msg == WM_DESTROY) +        { +            PostQuitMessage(0);  // Posts WM_QUIT with an exit code of 0 +            return 0; +        }      }      // pass unhandled messages down to Windows @@ -4579,25 +4594,11 @@ std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList()  #endif // LL_WINDOWS  inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread() -    : LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, true /*should be false, temporary workaround for SL-18721*/) +    : LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, false)  {      LL::ThreadPool::start();  } -void LLWindowWin32::LLWindowWin32Thread::close() -{ -    if (!mQueue->isClosed()) -    { -        LL_WARNS() << "Closing window thread without using destroy_window_handler" << LL_ENDL; -        LL::ThreadPool::close(); - -        // Workaround for SL-18721 in case window closes too early and abruptly -        LLSplashScreen::show(); -        LLSplashScreen::update("..."); // will be updated later -    } -} - -  /**   * LogChange is to log changes in status while trying to avoid spamming the   * log with repeated messages, especially in a tight loop. It refuses to log @@ -4812,108 +4813,105 @@ void LLWindowWin32::LLWindowWin32Thread::run()          }  #endif      } + +    destroyWindow(); + +    if (mDeleteOnExit) +    { +        delete this; +    } +} + +void LLWindowWin32::LLWindowWin32Thread::destroyWindow() +{ +    if (mWindowHandleThrd != NULL && IsWindow(mWindowHandleThrd)) +            { +                if (mhDCThrd) +                { +                    if (!ReleaseDC(mWindowHandleThrd, mhDCThrd)) +                    { +                        LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL; +                    } +                    mhDCThrd = NULL; +                } + +                // This causes WM_DESTROY to be sent *immediately* +                if (!destroy_window_handler(mWindowHandleThrd)) +                { +                    LL_WARNS("Window") << "Failed to destroy Window! " << std::hex << GetLastError() << LL_ENDL; +                } +            } +            else +            { +                // Something killed the window while we were busy destroying gl or handle somehow got broken +                LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL; +            } +            mWindowHandleThrd = NULL; +            mhDCThrd = NULL;  } -void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() +bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()  {      if (mQueue->isClosed())      {          LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL; -        return; +        return false; +    } + +    // Hide the window immediately to prevent user interaction during shutdown +    if (mWindowHandleThrd) +    { +        ShowWindow(mWindowHandleThrd, SW_HIDE);      } -    // Make sure we don't leave a blank toolbar button. -    // Also hiding window now prevents user from suspending it -    // via some action (like dragging it around) -    ShowWindow(mWindowHandleThrd, SW_HIDE); +    mGLReady = false; -    // Schedule destruction +    // Capture current handle before we lose it      HWND old_handle = mWindowHandleThrd; -    post([this]() -         { -             if (IsWindow(mWindowHandleThrd)) -             { -                 if (mhDCThrd) -                 { -                     if (!ReleaseDC(mWindowHandleThrd, mhDCThrd)) -                     { -                         LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL; -                     } -                     mhDCThrd = NULL; -                 } - -                 // This causes WM_DESTROY to be sent *immediately* -                 if (!destroy_window_handler(mWindowHandleThrd)) -                 { -                     LL_WARNS("Window") << "Failed to destroy Window! " << std::hex << GetLastError() << LL_ENDL; -                 } -             } -             else -             { -                 // Something killed the window while we were busy destroying gl or handle somehow got broken -                 LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL; -             } -             mWindowHandleThrd = NULL; -             mhDCThrd = NULL; -             mGLReady = false; -         }); +    // Clear the user data to prevent callbacks from finding us +    if (old_handle) +    { +        SetWindowLongPtr(old_handle, GWLP_USERDATA, NULL); +    } + +    // Signal thread to clean up when done +    mDeleteOnExit = true; + +    // Close the queue first      LL_DEBUGS("Window") << "Closing window's pool queue" << LL_ENDL;      mQueue->close(); -    // Post a nonsense user message to wake up the thread in -    // case it is waiting for a getMessage() +    // Wake up the thread if it's stuck in GetMessage()      if (old_handle)      {          WPARAM wparam{ 0xB0B0 };          LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle              << ", " << WM_DUMMY_              << ", " << wparam << ")" << std::dec << LL_ENDL; -        PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337); -    } -    // There are cases where window will refuse to close, -    // can't wait forever on join, check state instead -    LLTimer timeout; -    timeout.setTimerExpirySec(2.0); -    while (!getQueue().done() && !timeout.hasExpired() && mWindowHandleThrd) -    { -        ms_sleep(100); +        // Use PostMessage to signal thread to wake up +        PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337);      } -    if (getQueue().done() || mWindowHandleThrd == NULL) +    // Cleanly detach threads instead of joining them to avoid blocking the main thread +    // This is acceptable since the thread will self-delete with mDeleteOnExit +    for (auto& pair : mThreads)      { -        // Window is closed, started closing or is cleaning up -        // now wait for our single thread to die. -        if (mWindowHandleThrd) -        { -            LL_INFOS("Window") << "Window is closing, waiting on pool's thread to join, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL; +        try { +            // Only detach if the thread is joinable +            if (pair.second.joinable()) +            { +                pair.second.detach(); +            }          } -        else -        { -            LL_DEBUGS("Window") << "Waiting on pool's thread, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL; -        } -        for (auto& pair : mThreads) -        { -            pair.second.join(); +        catch (const std::system_error& e) { +            LL_WARNS("Window") << "Exception detaching thread: " << e.what() << LL_ENDL;          }      } -    else -    { -        // Something suspended window thread, can't afford to wait forever -        // so kill thread instead -        // Ex: This can happen if user starts dragging window arround (if it -        // was visible) or a modal notification pops up -        LL_WARNS("Window") << "Window is frozen, couldn't perform clean exit" << LL_ENDL; -        for (auto& pair : mThreads) -        { -            // very unsafe -            TerminateThread(pair.second.native_handle(), 0); -            pair.second.detach(); -        } -    }      LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL; +    return true;  }  void LLWindowWin32::post(const std::function<void()>& func) | 
