diff --git a/.github/workflows/build_viewer.yml b/.github/workflows/build_viewer.yml index 8bc2ae7010..f56452fb47 100644 --- a/.github/workflows/build_viewer.yml +++ b/.github/workflows/build_viewer.yml @@ -2,84 +2,181 @@ name: Build viewer on: push env: AUTOBUILD_VARIABLES_FILE: ${{github.workspace}}/build-variables/variables - EXTRA_ARGS: -DFMODSTUDIO=Off -DUSE_KDU=Off + EXTRA_ARGS: -DFMODSTUDIO=ON -DUSE_KDU=ON --crashreporting + build_secrets_checkout: ${{github.workspace}}/signing + jobs: build_matrix: strategy: matrix: - os: [macos-11,ubuntu-18.04,windows-2022] + os: [macos-10.15,ubuntu-18.04,windows-2022] grid: [sl,os] addrsize: [64,32] exclude: - os: ubuntu-18.04 addrsize: 32 - - os: macos-11 + - os: macos-10.15 addrsize: 32 runs-on: ${{ matrix.os }} steps: - - name: Set OS flag - if: matrix.grid == 'os' - run: echo "FS_GRID=-DOPENSIM:BOOL=ON" >> $GITHUB_ENV - shell: bash + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + if: runner.os != 'Windows' + id: py311 + with: + python-version: '3.11' + cache: 'pip' + - run: pip3 install -r requirements.txt + - name: Check python version + run: python -V + - name: Checkout build var + uses: actions/checkout@v3 + with: + repository: FirestormViewer/fs-build-variables + path: build-variables + - name: Setup rclone and download the folder + uses: beqjanus/setup-rclone@main + with: + rclone_config: ${{ secrets.RCLONE_CONFIG }} - - name: Set SL flag - if: matrix.grid == 'sl' - run: echo "FS_GRID=-DOPENSIM:BOOL=OFF" >> $GITHUB_ENV - shell: bash - - - name: Get the code - uses: actions/checkout@v3 - with: - fetch-depth: 1 + - name: Set OS flag + if: matrix.grid == 'os' + run: echo "FS_GRID=-DOPENSIM:BOOL=ON" >> $GITHUB_ENV + shell: bash - - name: Checkout build var - uses: actions/checkout@v3 - with: - repository: FirestormViewer/fs-build-variables - path: build-variables + - name: Set channel name + if: matrix.addrsize == '64' + run: echo "FS_RELEASE_CHAN=Releasex64" >> $GITHUB_ENV + shell: bash + + - name: Set channel name for 32 bit + if: matrix.addrsize == '32' + run: echo "FS_RELEASE_CHAN=Release" >> $GITHUB_ENV + shell: bash + + - name: Set SL flag + if: matrix.grid == 'sl' + run: echo "FS_GRID=-DOPENSIM:BOOL=OFF -DHAVOK_TPV:BOOL=ON" >> $GITHUB_ENV + shell: bash - - name: set VSVER for Windows builds - if: runner.os == 'Windows' - run: echo "AUTOBUILD_VSVER=170" >> $GITHUB_ENV - shell: bash + - name: Get the code + uses: actions/checkout@v3 + with: + fetch-depth: 0 - - name: Install required Ubuntu packages - if: runner.os == 'Linux' - run: sudo apt-get install python3-setuptools mesa-common-dev libgl1-mesa-dev libxinerama-dev libxrandr-dev libpulse-dev libglu1-mesa-dev + - name: Checkout build var + uses: actions/checkout@v3 + with: + repository: FirestormViewer/fs-build-variables + path: build-variables - - name: install autobuild - run: pip3 install git+https://github.com/Nicky-D/autobuild@main_nd + - name: rclone the private 3p packages on Windows + if: runner.os == 'Windows' + run: 'rclone copy fs_bundles: --include "*windows*bz2" .' + - name: rclone the private 3p packages on MacOS + if: runner.os == 'MacOS' + run: 'rclone copy fs_bundles: --include "*darwin*bz2" .' + - name: rclone the private 3p packages on Linux + if: runner.os == 'Linux' + run: 'rclone copy fs_bundles: --include "*linux*bz2" .' - - name: install autobuild - run: pip3 install llbase + - name: set VSVER for Windows builds + if: runner.os == 'Windows' + run: echo "AUTOBUILD_VSVER=170" >> $GITHUB_ENV + shell: bash + - name: Install certificate + if: runner.os == 'macOS' + env: + FS_CERT: ${{ secrets.FS_CERT }} + FS_CERT_PASS: ${{ secrets.FS_CERT_PASS }} + FS_KEYCHAIN_PASS: ${{ secrets.FS_KEYCHAIN_PASS }} + NOTARIZE_CREDS: ${{ secrets.NOTARIZE_CREDS }} + run: | + mkdir -p ${build_secrets_checkout}/code-signing-osx + echo -n "$FS_CERT" | base64 --decode --output ${build_secrets_checkout}/code-signing-osx/fs-cert.p12 + echo -n "$FS_CERT_PASS" >${build_secrets_checkout}/code-signing-osx/password.txt + echo -n "$NOTARIZE_CREDS" | base64 --decode --output ${build_secrets_checkout}/code-signing-osx/notarize_creds.sh + security create-keychain -p "$FS_KEYCHAIN_PASS" ~/Library/Keychains/viewer.keychain + security set-keychain-settings -lut 21600 ~/Library/Keychains/viewer.keychain + security unlock-keychain -p "$FS_KEYCHAIN_PASS" ~/Library/Keychains/viewer.keychain + security import ${build_secrets_checkout}/code-signing-osx/fs-cert.p12 -P "$FS_CERT_PASS" -A -t cert -f pkcs12 -k ~/Library/Keychains/viewer.keychain + security set-key-partition-list -S apple-tool:,apple:, -s -k "$FS_KEYCHAIN_PASS" -t private ~/Library/Keychains/viewer.keychain + security list-keychain -d user -s ~/Library/Keychains/viewer.keychain + - name: Install required Ubuntu packages + if: runner.os == 'Linux' + run: sudo apt-get install python3-setuptools mesa-common-dev libgl1-mesa-dev libxinerama-dev libxrandr-dev libpulse-dev libglu1-mesa-dev + - name: install autobuild + run: pip3 install git+https://github.com/Nicky-D/autobuild@main_nd - - name: Configure - run: autobuild configure -c ReleaseFS -A${{matrix.addrsize}} -- --package --chan ${{github.ref_name}} ${{env.EXTRA_ARGS}} ${{env.FS_GRID}} - shell: bash - - - name: build - run: autobuild build -c ReleaseFS -A${{matrix.addrsize}} --no-configure - shell: bash + - name: install autobuild + run: pip3 install llbase - - name: publish ${{ matrix.os }} artifacts - if: runner.os == 'Windows' - uses: actions/upload-artifact@v3 - with: - name: ${{ matrix.os }}-${{matrix.addrsize}}-${{matrix.grid}}-artifacts.zip - path: | - build-*/newview/Release/*Setup.exe - build-*/newview/Release/*.xz + - name: edit installables (64 bit) + if: runner.os == 'Windows' && matrix.addrsize == 64 + run: | + autobuild installables edit llphysicsextensions_tpv platform=windows${{matrix.addrsize}} url='file:///\${{ github.workspace }}\llphysicsextensions_tpv-1.0.571939-windows${{matrix.addrsize}}-571939.tar.bz2' + autobuild installables edit fmodstudio platform=windows${{matrix.addrsize}} url='file:///\${{ github.workspace }}\fmodstudio-2.02.09-windows${{matrix.addrsize}}-222890941.tar.bz2' + shell: bash - - name: publish ${{ matrix.os }} artifacts - if: runner.os == 'Linux' - uses: actions/upload-artifact@v3 - with: - name: ${{ matrix.os }}-${{matrix.addrsize}}-${{matrix.grid}}-artifacts.zip - path: build-linux-*/newview/*.xz + - name: edit installables (32 bit) + if: runner.os == 'Windows' && matrix.addrsize == 32 + run: | + autobuild installables edit llphysicsextensions_tpv platform=windows url='file:///\${{ github.workspace }}\llphysicsextensions_tpv-1.0.571939-windows-571939.tar.bz2' + autobuild installables edit fmodstudio platform=windows url='file:///\${{ github.workspace }}\fmodstudio-2.02.09-windows-222890940.tar.bz2' + shell: bash - - name: publish ${{ matrix.os }} artifacts - if: runner.os == 'macOS' - uses: actions/upload-artifact@v3 - with: - name: ${{ matrix.os }}-${{matrix.addrsize}}-${{matrix.grid}}-artifacts.zip - path: build-darwin-*/newview/*.dmg + - name: edit installables (32/64 agnostic) + if: runner.os == 'Windows' + run: | + autobuild installables edit kdu platform=windows url='file:///\${{ github.workspace }}\kdu-8.2-windows-212351246.tar.bz2' + shell: bash + + - name: edit installables + if: runner.os == 'macOS' + run: | + autobuild installables edit llphysicsextensions_tpv platform=darwin${{matrix.addrsize}} url='file:////${{ github.workspace }}/llphysicsextensions_tpv-1.0.571939-darwin${{matrix.addrsize}}-571939.tar.bz2' + autobuild installables edit kdu platform=darwin url='file:////${{ github.workspace }}/kdu-8.2-darwin-212431232.tar.bz2' + autobuild installables --debug edit fmodstudio platform=darwin${{matrix.addrsize}} url='file:////${{ github.workspace }}/fmodstudio-2.02.09-darwin${{matrix.addrsize}}-5.tar.bz2' + shell: bash + + - name: edit installables + if: runner.os == 'Linux' + run: | + autobuild installables edit kdu platform=linux${{matrix.addrsize}} url='file:////${{ github.workspace }}/kdu-8.2-linux${{matrix.addrsize}}_bionic-220911445.tar.bz2' + autobuild installables edit fmodstudio platform=linux${{matrix.addrsize}} url='file:////${{ github.workspace }}/fmodstudio-2.02.09-linux${{matrix.addrsize}}-222891103.tar.bz2' + shell: bash + + - name: Configure + run: autobuild configure --debug -c ReleaseFS -A${{matrix.addrsize}} -- --package --chan ${{env.FS_RELEASE_CHAN}} ${{env.EXTRA_ARGS}} ${{env.FS_GRID}} + shell: bash + + - name: build + run: autobuild build --debug -c ReleaseFS -A${{matrix.addrsize}} --no-configure + shell: bash + + - name: publish Windows artifacts + if: runner.os == 'Windows' + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.os }}-${{matrix.addrsize}}-${{matrix.grid}}-artifacts.zip + path: | + build-*/newview/Release/*Setup.exe + build-*/newview/Release/*.xz + + - name: publish Linux artifacts + if: runner.os == 'Linux' + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.os }}-${{matrix.addrsize}}-${{matrix.grid}}-artifacts.zip + path: | + build-linux-*/newview/*.xz + build-linux-*/newview/*.bz2 + + - name: publish MacOS artifacts + if: runner.os == 'macOS' + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.os }}-${{matrix.addrsize}}-${{matrix.grid}}-artifacts.zip + path: | + build-darwin-*/newview/*.dmg + build-darwin-*/newview/*.bz2 diff --git a/FIRESTORM-SOURCE_LICENSE_HEADER.txt b/FIRESTORM-SOURCE_LICENSE_HEADER.txt index 77797473c5..19eedbfa2e 100644 --- a/FIRESTORM-SOURCE_LICENSE_HEADER.txt +++ b/FIRESTORM-SOURCE_LICENSE_HEADER.txt @@ -2,7 +2,7 @@ * @file * @brief * - * $LicenseInfo:firstyear=2022&license=fsviewerlgpl$ + * $LicenseInfo:firstyear=2023&license=fsviewerlgpl$ * Phoenix Firestorm Viewer Source Code * Copyright (C) 2020, The Phoenix Firestorm Project, Inc. * diff --git a/autobuild.xml b/autobuild.xml index b5a9efc566..13181bc9ee 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3427,7 +3427,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors canonical_repo https://github.com/secondlife/viewer copyright - Copyright (c) 2022, The Phoenix Firestorm Project, Inc. + Copyright (c) 2023, The Phoenix Firestorm Project, Inc. description Firestorm Viewer license diff --git a/fsutils/download_list.py b/fsutils/download_list.py new file mode 100644 index 0000000000..5981e7c511 --- /dev/null +++ b/fsutils/download_list.py @@ -0,0 +1,211 @@ +#!/bin/python3 +import argparse +import os +import sys +import time +import zipfile +import glob +import shutil + +# iterate over the files in a directory and pass them to a command line subshell +def get_files(path): + files = [] + for root, dirs, files in os.walk(path): + # print(f"Found : {files}") + return files + return None + + +# run a command line subshell and return the output + +# We want to get the following output by looping over the files +# DOWNLOADS +# ------------------------------------------------------------------------------------------------------- + +# Windows for SL 64 bit +# https://downloads.firestormviewer.org/preview/windows/Phoenix-Firestorm-Releasex64-6-6-8-68355_Setup.exe + +# MD5: 3094776F5DB11B6A959B0F3AED068C6A + +# Windows for SL 32 bit +# https://downloads.firestormviewer.org/preview/windows/Phoenix-Firestorm-Release-6-6-8-68355_Setup.exe + +# MD5: 2F960B3353971FFF63307B5210D306F5 + +# Windows for Opensim 64bit +# https://downloads.firestormviewer.org/preview/windows/Phoenix-FirestormOS-Releasex64-6-6-8-68355_Setup.exe + +# MD5: 6218D7B826538BB956699F9581532ECE + +# Windows for Opensim 32bit +# https://downloads.firestormviewer.org/preview/windows/Phoenix-FirestormOS-Release-6-6-8-68355_Setup.exe + +# MD5: D636CAFD287B4C8B96D726FE2A145327 + +# ------------------------------------------------------------------------------------------------------- +# Mac OSX for SL +# https://downloads.firestormviewer.org/preview/mac/Phoenix-Firestorm-Releasex64-6-6-8-68355.dmg + +# MD5: DA5AF534690328078B0B7BCEEA8D6959 + +# Mac OSX for Opensim +# https://downloads.firestormviewer.org/preview/mac/Phoenix-FirestormOS-Releasex64-6-6-8-68355.dmg + +# MD5: 16CA020E73760D8205E2314D07EEC90E + +# ------------------------------------------------------------------------------------------------------- +# Linux for SL +# https://downloads.firestormviewer.org/preview/linux/Phoenix-Firestorm-Releasex64-6-6-8-68355.tar.xz + +# MD5: 1A0C50065077B92889FFBC651E4278E4 + +# Linux for Opensim +# https://downloads.firestormviewer.org/preview/linux/Phoenix-FirestormOS-Releasex64-6-6-8-68355.tar.xz + +# MD5: 9D5D8021F376194B42F6E7D8E537E45E + +# ------------------------------------------------------------------------------------------------------- + +def run_cmd(cmd): + # print(cmd) + return os.popen(cmd).read() + +#using the md5sum command get the md5 for the file + +def get_md5(mdfile): + # print(f"mdfile is {mdfile}") + md5sum = run_cmd(f"md5sum {mdfile}") + #split md5sum on space + md5sum = md5sum.split()[0] + #remove leading '\' + md5sum = md5sum[1:] + return md5sum + +def unzip_file(zip_file, unzip_dir): + with zipfile.ZipFile(zip_file, 'r') as zip_ref: + zip_ref.extractall(unzip_dir) + +def flatten_tree(tree_root): + for root, flatten_dirs, files in os.walk(tree_root, topdown=False): + for file in files: + # Construct the full path to the file + file_path = os.path.join(root, file) + # Move the file to the root directory + shutil.move(file_path, tree_root) + for dir in flatten_dirs: + # Construct the full path to the subdirectory + subdir_path = os.path.join(root, dir) + # Delete the subdirectory and its contents + shutil.rmtree(subdir_path) + + +# parse args first arg optional -r (release) second arg mandatory string path_to_directory + +parser = argparse.ArgumentParser( + prog="print_download_list", + description="Prints the list of files for download and their md5 checksums" + ) +parser.add_argument("-r", "--release", required=False, default=False, action="store_true", help="use the release folder in the target URL") +parser.add_argument("-u", "--unzip", required=False, default=False, action="store_true", help="unzip the github artifact first") +# add path_to_directory required parameter to parser +parser.add_argument("path_to_directory", help="path to the directory in which we'll look for the files") + +args = parser.parse_args() +path_to_directory = args.path_to_directory +release = args.release + +dirs = ["windows", "mac", "linux"] + +if args.unzip: + # unzip the github artifact for this OS (`dir`) into the folder `dir` + # get the .zip files in args.path_to_directory using glob + zips = glob.glob(f"{args.path_to_directory}/*.zip") + for file in zips: + # print(f"unzipping {file}") + if "ubuntu" in file.lower(): + unzip_file(file, os.path.join(args.path_to_directory, "linux")) + if "windows" in file.lower(): + unzip_file(file, os.path.join(args.path_to_directory, "windows")) + if "macos" in file.lower(): + unzip_file(file, os.path.join(args.path_to_directory, "mac")) + for dir in dirs: + flatten_tree(os.path.join(args.path_to_directory, dir)) + # Now move the symbols files to the symbols folder + symbols_folder = os.path.join(args.path_to_directory, "symbols") + os.mkdir(symbols_folder) + # Traverse the directory tree and move all of the files to the root directory + symbol_archives = glob.glob(f"{args.path_to_directory}/**/*_hvk*", recursive=True) + for sym_file in symbol_archives: + print(f"Moving {sym_file} to {symbols_folder}") + shutil.move(sym_file, symbols_folder) + symbol_archives = glob.glob(f"{args.path_to_directory}/**/*_oss*", recursive=True) + for sym_file in symbol_archives: + print(f"Moving {sym_file} to {symbols_folder}") + shutil.move(sym_file, symbols_folder) + + +file_dict = {} +md5_dict = {} + +for dir in dirs: + dir = dir.lower() + files = get_files(os.path.join(args.path_to_directory, dir)) + for file in files: + full_file = os.path.join(args.path_to_directory, dir, file) + md5 = get_md5(full_file) + base_name = os.path.basename(file) + if "-Release-" in base_name: + wordsize = "32" + else: + wordsize = "64" + + if "FirestormOS-" in base_name: + grid = "OS" + else: + grid = "SL" + + if dir in dirs: + file_dict[f"{grid}{dir}{wordsize}"] = full_file + md5_dict[f"{grid}{dir}{wordsize}"] = md5 + +download_root_preview = "https://downloads.firestormviewer.org/preview" +download_root_release = "https://downloads.firestormviewer.org/release" + +if args.release: + download_root = download_root_release +else: + download_root = download_root_preview + +print(''' +DOWNLOADS''') + +platforms_printable = {"windows":"MS Windows", "mac":"MacOS", "linux":"Linux"} +grids_printable = {"SL":"Second Life", "OS":"OpenSim"} + +for dir in dirs: + print(f'''------------------------------------------------------------------------------------------------------- +{platforms_printable[dir]} +''') + dir=dir.lower() + wordsize = "64" + platform = f"{platforms_printable[dir]}" + for grid in ["SL", "OS"]: + grid_printable = f"{grids_printable[grid]}" + print (f"{platform} for {grid_printable} ({wordsize}-bit)") + print ( "{}/{}/{}".format(download_root,dir,os.path.basename(file_dict[f"{grid}{dir}{wordsize}"])) ) + print () + print ( "MD5: {}".format(md5_dict[f"{grid}{dir}{wordsize}"]) ) + print () + if(dir == "windows"): + # Need to do 32 bit as well + wordsize = "32" + print (f"{platform} for {grid_printable} ({wordsize}-bit)") + print ( "{}/{}/{}".format(download_root,dir,os.path.basename(file_dict[f"{grid}{dir}{wordsize}"])) ) + print () + print ( "MD5: {}".format(md5_dict[f"{grid}{dir}{wordsize}"]) ) + print () + wordsize = "64" + +print(''' +-------------------------------------------------------------------------------------------------------''') + diff --git a/fsutils/parse_avatar_lad.py b/fsutils/parse_avatar_lad.py new file mode 100644 index 0000000000..3e15a07922 --- /dev/null +++ b/fsutils/parse_avatar_lad.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + +# open the avatar_lad.xml file and load it as a dom object + +from xml.dom import minidom +import os +import sys +import argparse + +parser = argparse.ArgumentParser() +# add positional argument for avatar_lad.xml +parser.add_argument("avatar_lad", help="path to avatar_lad.xml file") + +args = parser.parse_args() + + +# using minidom open the avatar_lad.xml file and load it as a dom object + + +# open the avatar_lad.xml file and load it as a dom object + +dom = minidom.parse(open(args.avatar_lad, "rb")) + + +# get the first element in the dom object + +root = dom.documentElement + +# find the "skeleton" child node +skeleton = root.getElementsByTagName("skeleton")[0] + + +for child in skeleton.childNodes: + if child.nodeType == child.ELEMENT_NODE: + # if tagname is "attachment_point" and 'hud' attribute doesn't exist print id and name + if child.tagName == "attachment_point": + if not child.hasAttribute("hud"): + print(f"{child.getAttribute('id')} - {child.getAttribute('name')}") + else: + print(f"{child.getAttribute('id')} - [HUD] {child.getAttribute('name')}") + + diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h index 16b3966ad2..8329041a5c 100644 --- a/indra/llcommon/llthreadsafequeue.h +++ b/indra/llcommon/llthreadsafequeue.h @@ -180,7 +180,7 @@ protected: typedef QueueT queue_type; QueueT mStorage; U32 mCapacity; - bool mClosed; + std::atomic mClosed; // Try harder to stop the compiler optimising the mClosed state inside the loops boost::fibers::timed_mutex mLock; typedef std::unique_lock lock_t; @@ -308,7 +308,13 @@ bool LLThreadSafeQueue::push_(lock_t& lock, T&& element) { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; if (mStorage.size() >= mCapacity) + // Make thread queue capacity hangs visible + // return false; + { + LL_WARNS("ThreadPool") << "Threadsafe queue push_(lockacquired) queue full " << mStorage.size() << " >= " << mCapacity << LL_ENDL; return false; + } + // mStorage.push(std::forward(element)); lock.unlock(); @@ -336,7 +342,13 @@ bool LLThreadSafeQueue::pushIfOpen(T&& element) return true; // Storage Full. Wait for signal. - mCapacityCond.wait(lock1); + // [FIRE-32453][BUG-232971] Improve shutdown behaviour. Time bound the sleep + // mCapacityCond.wait(lock1); + // When the queue is full and the consuming thread has exited we would never wake up. + // For safety, we now wait max half a second then recheck close. + const auto timeout = std::chrono::milliseconds(500); + mCapacityCond.wait_for(lock1, timeout); + // } } diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h index f8eec3b457..e995d9331e 100644 --- a/indra/llcommon/threadpool.h +++ b/indra/llcommon/threadpool.h @@ -46,7 +46,10 @@ namespace LL * ThreadPool listens for application shutdown messages on the "LLApp" * LLEventPump. Call close() to shut down this ThreadPool early. */ - void close(); + // [FIRE-32453][BUG-232971] Improve shutdown behaviour. + // void close(); + virtual void close(); + // std::string getName() const { return mName; } size_t getWidth() const { return mThreads.size(); } @@ -61,7 +64,8 @@ namespace LL private: void run(const std::string& name); - + + protected: // [FIRE-32453][BUG-232971] Improve shutdown behaviour. WorkQueue mQueue; std::string mName; size_t mThreadCount; diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index cbfdc5befa..156d9f5e7b 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -845,7 +845,7 @@ LLSD LLModel::writeModel( mdl[model_names[idx]][i]["TriangleList"] = indices; - if (skinning) + if (skinning && idx != LLModel::LOD_PHYSICS) { //write out skin weights diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index 899ae77929..457fe29c72 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -505,7 +505,12 @@ attributedStringInfo getSegments(NSAttributedString *str) // e.g. OS Window for upload something or Input Window... // mModifiers instance variable is for insertText: or insertText:replacementRange: (by Pell Smit) mModifiers = [theEvent modifierFlags]; - unichar ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0]; + NSString *str_no_modifiers = [theEvent charactersIgnoringModifiers]; + unichar ch = 0; + if (str_no_modifiers.length) + { + ch = [str_no_modifiers characterAtIndex:0]; + } bool acceptsText = mHasMarkedText ? false : callKeyDown(&eventData, keycode, mModifiers, ch); if (acceptsText && diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 5a85dabac3..f146b71b6e 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -37,6 +37,7 @@ #include "llwindowcallbacks.h" // Linden library includes +#include "llapp.h" // [FIRE-32453][BUG-232971] Improve shutdown behaviour. #include "llerror.h" #include "llexception.h" #include "llfasttimer.h" @@ -88,6 +89,7 @@ const UINT WM_DUMMY_(WM_USER + 0x0017); const UINT WM_POST_FUNCTION_(WM_USER + 0x0018); extern BOOL gDebugWindowProc; +extern BOOL gDisconnected; // [FIRE-32453][BUG-232971] Improve shutdown behaviour. static std::thread::id sWindowThreadId; static std::thread::id sMainThreadId; @@ -346,6 +348,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool LLWindowWin32Thread(); void run() override; + void close() override; // [FIRE-32453][BUG-232971] Improve shutdown behaviour. /// called by main thread to post work to this window thread template @@ -353,6 +356,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool { try { + LL_DEBUGS("Window") << "post( callable ) to work queue" << LL_ENDL; // extra debug for threaded window handler getQueue().post(std::forward(func)); } catch (const LLThreadSafeQueueInterrupt&) @@ -897,9 +901,12 @@ void LLWindowWin32::close() // This causes WM_DESTROY to be sent *immediately* if (!destroy_window_handler(mWindowHandle)) { - OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"), - mCallbacks->translateString("MBShutdownErr"), - OSMB_OK); + // Can't use a message box here because we're about to stop servicing the events. + // OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"), + // mCallbacks->translateString("MBShutdownErr"), + // OSMB_OK); + LL_INFOS("Window") << "Destroying Window failed" << LL_ENDL; + // } } else @@ -918,6 +925,10 @@ void LLWindowWin32::close() // operations we're asking. That's the last time WE should touch it. mhDC = NULL; mWindowHandle = NULL; + // [FIRE-32453][BUG-232971] close the related queues first to prevent spinning. + mFunctionQueue.close(); + mMouseQueue.close(); + // mWindowThread->close(); } @@ -4734,11 +4745,45 @@ private: std::string mPrev; }; +// [FIRE-32453][BUG-232971] Improve shutdown behaviour. +// Provide a close() override that ignores the initial close triggered by the threadpool detecting "quit" +// but waits for the viewer to be disconected and the second close call triggered by the app window destructor +void LLWindowWin32::LLWindowWin32Thread::close() +{ + assert_main_thread(); + if (! mQueue.isClosed() && gDisconnected) + { + LL_DEBUGS("ThreadPool") << mName << " closing queue and joining threads" << LL_ENDL; + mQueue.close(); + for (auto& pair: mThreads) + { + LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL; + // As we cannot seem to rely on the clean and timely exit of the windows thread in ALL situations we apply a timeout. + std::future f = std::async(std::launch::async, [&] { pair.second.join(); }); + if (f.wait_until(std::chrono::steady_clock::now() + std::chrono::seconds(5)) == std::future_status::ready) { + LL_DEBUGS("ThreadPool") << mName << " joined normally." << LL_ENDL; + } else { + LL_WARNS("ThreadPool") << mName << " join timed out." << LL_ENDL; + // the specified time point was reached before the thread finished execution and could be joined + } + } + LL_DEBUGS("ThreadPool") << mName << " shutdown complete" << LL_ENDL; + } + else + { + LL_DEBUGS("ThreadPool") << mName << " shutdown request ignored - not yet disconneced." << LL_ENDL; + } +} +// + void LLWindowWin32::LLWindowWin32Thread::run() { sWindowThreadId = std::this_thread::get_id(); LogChange logger("Window"); - + // [FIRE-32453][BUG-232971] Improve shutdown behaviour. + try + { + // while (! getQueue().done()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; @@ -4765,18 +4810,31 @@ void LLWindowWin32::LLWindowWin32Thread::run() ", ", msg.wParam, ")"); TranslateMessage(&msg); DispatchMessage(&msg); - - mMessageQueue.pushFront(msg); + // [FIRE-32453][BUG-232971] Improve shutdown behaviour. + // mMessageQueue.pushFront(msg); + try + { + // Nobody is reading this queue once we are quitting. Writing to it causes a hang. + if(!LLApp::isQuitting()) + mMessageQueue.pushFront(msg); + } + catch (const LLThreadSafeQueueInterrupt&) + { + // Shutdown timing is tricky. The main thread can end up trying + // to post a cursor position after having closed the WorkQueue. + logger.always("Message procesing tried to push() to closed MessageQueue - caught"); + } + // } } { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Function Queue"); - logger.onChange("runPending()"); + logger.onChange("runPending()"); //process any pending functions getQueue().runPending(); } - + #if 0 { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Sleep"); @@ -4785,16 +4843,42 @@ void LLWindowWin32::LLWindowWin32Thread::run() } #endif } + // [FIRE-32453][BUG-232971] Improve shutdown behaviour. + } + catch (const std::exception& e) + { + logger.always("Windows thread exiting - Exception: ", e.what()); + } + catch (...) + { + logger.always("Windows thread exiting - Exception: Unknown"); + } + logger.always("done - queue closed on windows thread."); + // } void LLWindowWin32::post(const std::function& func) { - mFunctionQueue.pushFront(func); + try + { + mFunctionQueue.pushFront(func); + } + catch (const LLThreadSafeQueueInterrupt&) + { + LL_INFOS("Window") << "push function to closed Queue caught" << LL_ENDL; + } } void LLWindowWin32::postMouseButtonEvent(const std::function& func) { - mMouseQueue.pushFront(func); + try + { + mMouseQueue.pushFront(func); + } + catch (const LLThreadSafeQueueInterrupt&) + { + LL_INFOS("Window") << "push mouse event to closed Queue caught" << LL_ENDL; + } } void LLWindowWin32::kickWindowThread(HWND windowHandle) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 02d689ce66..f03cc01b48 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2681,7 +2681,7 @@ if (DARWIN) set(MACOSX_BUNDLE_BUNDLE_NAME "Firestorm") set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}") set(MACOSX_BUNDLE_BUNDLE_VERSION "${VIEWER_SHORT_VERSION}${VIEWER_MACOSX_PHASE}${VIEWER_REVISION}") - set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2010-2022 The Phoenix Firestorm Project, Inc.") + set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2010-2023 The Phoenix Firestorm Project, Inc.") set(MACOSX_BUNDLE_NSMAIN_NIB_FILE "Firestorm.nib") set(MACOSX_BUNDLE_NSPRINCIPAL_CLASS "LLApplication") diff --git a/indra/newview/English.lproj/InfoPlist.strings b/indra/newview/English.lproj/InfoPlist.strings index 4948632494..1afe5749be 100644 --- a/indra/newview/English.lproj/InfoPlist.strings +++ b/indra/newview/English.lproj/InfoPlist.strings @@ -3,4 +3,4 @@ CFBundleName = "Firestorm"; CFBundleShortVersionString = "Firestorm version %%VERSION%%"; -CFBundleGetInfoString = "Firestorm version %%VERSION%%, Copyright 2010-2022 The Phoenix Firestorm Project, Inc."; +CFBundleGetInfoString = "Firestorm version %%VERSION%%, Copyright 2010-2023 The Phoenix Firestorm Project, Inc."; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f7526af0fd..9f6e98f3a6 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2062,13 +2062,12 @@ bool LLAppViewer::cleanup() // Give any remaining SLPlugin instances a chance to exit cleanly. LLPluginProcessParent::shutdown(); - // [FIRE-32453] [BUG-232971] disconnect sooner to force the cache write. - // disconnectViewer(); - // LLViewerCamera::deleteSingleton(); - // LL_INFOS() << "Viewer disconnected" << LL_ENDL; + disconnectViewer(); LLViewerCamera::deleteSingleton(); - // + + LL_INFOS() << "Viewer disconnected" << LL_ENDL; + if (gKeyboard) { gKeyboard->resetKeys(); @@ -4870,10 +4869,6 @@ void LLAppViewer::removeDumpDir() void LLAppViewer::forceQuit() { - // [FIRE-32453] [BUG-232971] disconnect sooner to force the cache write. - disconnectViewer(); - LL_INFOS() << "Viewer disconnected" << LL_ENDL; - // LLApp::setQuitting(); } @@ -6344,12 +6339,7 @@ void LLAppViewer::idleNetwork() } } add(LLStatViewer::NUM_NEW_OBJECTS, gObjectList.mNumNewObjects); - // [FIRE-32453] [BUG-232971] disconnect sooner to force the cache write. - if(gDisconnected) - { - return; - } - // + // Retransmit unacknowledged packets. gXferManager->retransmitUnackedPackets(); gAssetStorage->checkForTimeouts(); @@ -6378,7 +6368,6 @@ void LLAppViewer::disconnectViewer() { return; } - gDisconnected = TRUE;// [FIRE-32453] [BUG-232971] disconnect sooner to force the cache write. // // Cleanup after quitting. // @@ -6461,7 +6450,7 @@ void LLAppViewer::disconnectViewer() LLDestroyClassList::instance().fireCallbacks(); cleanup_xfer_manager(); - // gDisconnected = TRUE; // [FIRE-32453] [BUG-232971] disconnect sooner to force the cache write. + gDisconnected = TRUE; // Pass the connection state to LLUrlEntryParcel not to attempt // parcel info requests while disconnected. diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 43872bcdb0..54d1a861ce 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -1446,7 +1446,7 @@ bool LLTextureFetchWorker::doWork(S32 param) else { mCanUseHTTP = false ; - LL_WARNS(LOG_TXT) << "Texture not available via HTTP: empty URL." << LL_ENDL; + LL_DEBUGS(LOG_TXT) << "Texture not available via HTTP: empty URL." << LL_ENDL; } } else diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc index 1f7a2b71e8..dd0da75631 100755 --- a/indra/newview/res/viewerRes.rc +++ b/indra/newview/res/viewerRes.rc @@ -161,7 +161,7 @@ BEGIN VALUE "FileDescription", "Firestorm" VALUE "FileVersion", "${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}.${VIEWER_VERSION_REVISION}" VALUE "InternalName", "Firestorm" - VALUE "LegalCopyright", "Copyright \251 2010-2022, The Phoenix Firestorm Project, Inc." + VALUE "LegalCopyright", "Copyright \251 2010-2023, The Phoenix Firestorm Project, Inc." VALUE "OriginalFilename", "Firestorm.exe" VALUE "ProductName", "Firestorm" VALUE "ProductVersion", "${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}.${VIEWER_VERSION_REVISION}" diff --git a/indra/newview/skins/default/xui/de/floater_im_session.xml b/indra/newview/skins/default/xui/de/floater_im_session.xml index b07b74bf4a..af8501117c 100644 --- a/indra/newview/skins/default/xui/de/floater_im_session.xml +++ b/indra/newview/skins/default/xui/de/floater_im_session.xml @@ -31,17 +31,6 @@