Rebased ref, commits from common ancestor: commit aa89a8ea06c819f0fc18fb12cff9ee34f7245b46 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 15 22:16:49 2017 +0200
Drop SystemTicks from scheduler logging If you want to see system ticks, add +SYSTEMTICKS to your SAL_LOG. Change-Id: I8d67fbc64873a800555866f34023ac83ddfb7f02 diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx index 4187af3f3e8b..7bb2fbcce645 100644 --- a/vcl/source/app/scheduler.cxx +++ b/vcl/source/app/scheduler.cxx @@ -332,15 +332,14 @@ bool Scheduler::ProcessTaskScheduling() { const Timer *timer = dynamic_cast<Timer*>( pSchedulerData->mpTask ); if ( timer ) - SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " " - << pSchedulerData << " " << *pSchedulerData << " " << *timer ); + SAL_INFO( "vcl.schedule", pSchedulerData << " " + << *pSchedulerData << " " << *timer ); else if ( pSchedulerData->mpTask ) - SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " " - << pSchedulerData << " " << *pSchedulerData - << " " << *pSchedulerData->mpTask ); + SAL_INFO( "vcl.schedule", pSchedulerData << " " + << *pSchedulerData << " " << *pSchedulerData->mpTask ); else - SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " " - << pSchedulerData << " " << *pSchedulerData << " (to be deleted)" ); + SAL_INFO( "vcl.schedule", pSchedulerData << " " + << *pSchedulerData << " (to be deleted)" ); // Should the Task be released from scheduling or stacked? if ( !pSchedulerData->mpTask || !pSchedulerData->mpTask->IsActive() @@ -392,8 +391,8 @@ next_entry: if ( pMostUrgent ) { - SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " " - << pMostUrgent << " invoke-in " << *pMostUrgent->mpTask ); + SAL_INFO( "vcl.schedule", pMostUrgent + << " invoke-in " << *pMostUrgent->mpTask ); Task *pTask = pMostUrgent->mpTask; @@ -421,8 +420,7 @@ next_entry: Lock( nLockCount ); pMostUrgent->mbInScheduler = false; - SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() << " " - << pMostUrgent << " invoke-out" ); + SAL_INFO( "vcl.schedule", pMostUrgent << " invoke-out" ); // eventually pop the scheduler stack // this just happens for nested calls, which renders all accounting @@ -489,20 +487,20 @@ void Task::Start() mpSchedulerData = pSchedulerData; AppendSchedulerData( rSchedCtx, pSchedulerData ); - SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() - << " " << mpSchedulerData << " added " << *this ); + SAL_INFO( "vcl.schedule", + mpSchedulerData << " added " << *this ); } else - SAL_INFO( "vcl.schedule", tools::Time::GetSystemTicks() - << " " << mpSchedulerData << " restarted " << *this ); + SAL_INFO( "vcl.schedule", + mpSchedulerData << " restarted " << *this ); - mpSchedulerData->mnUpdateTime = tools::Time::GetSystemTicks(); + mpSchedulerData->mnUpdateTime = tools::Time::GetSystemTicks(); } void Task::Stop() { - SAL_INFO_IF( mbActive, "vcl.schedule", tools::Time::GetSystemTicks() - << " " << mpSchedulerData << " stopped " << *this ); + SAL_INFO_IF( mbActive, "vcl.schedule", + mpSchedulerData << " stopped " << *this ); mbActive = false; } commit 3e71751b0a159c2fae4e33f795486fd8f7fdcae8 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 15 22:35:49 2017 +0200 Add +SYSTEMTICKS to log format Prefixes SAL_* output lines with tools::Time::GetSystemTicks(). Now we can drop this information from the scheduler log output. Change-Id: I4840d0d56dbb5df55edf08fe664faf3a344196d0 diff --git a/include/sal/log.hxx b/include/sal/log.hxx index c096d52a0e47..9b8e518db50a 100644 --- a/include/sal/log.hxx +++ b/include/sal/log.hxx @@ -235,7 +235,7 @@ inline char const * unwrapStream(SAL_UNUSED_PARAMETER StreamIgnore const &) { <switch> ::= <sense><item> <sense> ::= "+"|"-" <item> ::= <flag>|<level>("."<area>)? - <flag> ::= "TIMESTAMP"|"RELATIVETIMER" + <flag> ::= "TIMESTAMP"|"RELATIVETIMER"|"SYSTEMTICKS" <level> ::= "INFO"|"WARN" @endverbatim @@ -245,14 +245,16 @@ inline char const * unwrapStream(SAL_UNUSED_PARAMETER StreamIgnore const &) { "+INFO+WARN" is used instead (which in turn results in everything being output). - The "+TIMESTAMP" flag causes each output line (as selected by the level - switch(es)) to be prefixed by a timestamp like 2016-08-18:14:04:43. + The "+TIMESTAMP" flag causes each SAL_* output line to be prefixed by + a timestamp like 2016-08-18:14:04:43. - The "+RELATIVETIMER" flag causes each output line (as selected by - the level switch(es)) to be prefixed by a relative timestamp in - seconds since the first output line like 1.312. + The "+RELATIVETIMER" flag causes each SAL_* output line to be prefixed by + a relative timestamp in seconds since the first output line like 1.312. - If both +TIMESTAMP and +RELATIVETIMER are specified, they are + The "+SYSTEMTICKS" flag causes each SAL_* output line to be prefixed by + the current value of tools::Time::GetSystemTicks(). + + If +TIMESTAMP, +RELATIVETIMER and +SYSTEMTICKS are specified, they are output in that order. Specifying a flag with a negative sense has no effect. Specifying @@ -274,7 +276,7 @@ inline char const * unwrapStream(SAL_UNUSED_PARAMETER StreamIgnore const &) { SAL_INFO("other", ...) generate output, while calls like SAL_INFO("foo", ...) or SAL_INFO("foo.barzzz", ...) do not. - The generated log output consists of the optinal timestamp, the given level + The generated log output consists of the optional timestamp, the given level ("info" or "warn"), the given area, the process ID, the thread ID, the source file, and the source line number, each followed by a colon, followed by a space, the given message, and a newline. The precise format of the log diff --git a/sal/osl/all/log.cxx b/sal/osl/all/log.cxx index 1f0138f1266d..831a59ad8083 100644 --- a/sal/osl/all/log.cxx +++ b/sal/osl/all/log.cxx @@ -22,6 +22,8 @@ #include <fstream> #include "osl/thread.hxx" +#include "osl/mutex.hxx" +#include "osl/time.h" #include "rtl/string.h" #include "sal/detail/log.h" #include "sal/log.hxx" @@ -53,6 +55,22 @@ bool const sal_use_syslog = false; namespace { +enum OutputItem +{ + EMPTY, + TIMESTAMP, + RELATIVETIMER, + SYSTEMTICKS, + LAST, + COUNT = LAST - 1, +}; + +bool bParsedLogEnvironment = false; +osl::Mutex aParserMutex; +OutputItem aOutputList[ OutputItem::COUNT ] = { OutputItem::EMPTY, }; + +void parseLogEnvironment(); + bool equalStrings( char const * string1, std::size_t length1, char const * string2, std::size_t length2) @@ -61,7 +79,8 @@ bool equalStrings( } #if !defined ANDROID -char const * toString(sal_detail_LogLevel level) { +char const * toString(sal_detail_LogLevel level) +{ switch (level) { case SAL_DETAIL_LOG_LEVEL_INFO: return "info"; @@ -81,13 +100,15 @@ char const * toString(sal_detail_LogLevel level) { // the process is running": #if defined ANDROID -char const * getEnvironmentVariable() { +char const * getEnvironmentVariable() +{ return std::getenv("SAL_LOG"); } #else -char const * getEnvironmentVariable_(const char* env) { +char const * getEnvironmentVariable_(const char* env) +{ char const * p1 = std::getenv(env); if (p1 == nullptr) { return nullptr; @@ -99,98 +120,150 @@ char const * getEnvironmentVariable_(const char* env) { return p2; } -char const * getEnvironmentVariable() { +char const * getEnvironmentVariable() +{ static char const * env = getEnvironmentVariable_("SAL_LOG"); return env; } -char const * getLogFile() { +char const * getLogFile() +{ static char const * logFile = getEnvironmentVariable_("SAL_LOG_FILE"); return logFile; } -void maybeOutputTimestamp(std::ostringstream &s) { +void maybeOutputTimestamp(std::ostringstream &s) +{ + assert( bParsedLogEnvironment ); + for ( unsigned int i = 0; + i < OutputItem::COUNT && OutputItem::EMPTY != aOutputList[ i ]; + ++i ) + { + switch (aOutputList[ i ]) + { + case OutputItem::TIMESTAMP: + { + char ts[100]; + TimeValue systemTime; + osl_getSystemTime(&systemTime); + TimeValue localTime; + osl_getLocalTimeFromSystemTime(&systemTime, &localTime); + oslDateTime dateTime; + osl_getDateTimeFromTimeValue(&localTime, &dateTime); + struct tm tm; + tm.tm_sec = dateTime.Seconds; + tm.tm_min = dateTime.Minutes; + tm.tm_hour = dateTime.Hours; + tm.tm_mday = dateTime.Day; + tm.tm_mon = dateTime.Month - 1; + tm.tm_year = dateTime.Year - 1900; + strftime(ts, sizeof(ts), "%Y-%m-%d:%H:%M:%S", &tm); + char milliSecs[11]; + sprintf(milliSecs, "%03u", static_cast<unsigned>(dateTime.NanoSeconds/1000000)); + s << ts << '.' << milliSecs << ':'; + break; + } // case OutputItem::TIMESTAMP + + case OutputItem::RELATIVETIMER: + { + static bool beenHere = false; + static TimeValue first; + if (!beenHere) { + osl_getSystemTime(&first); + beenHere = true; + } + TimeValue now; + osl_getSystemTime(&now); + int seconds = now.Seconds - first.Seconds; + int milliSeconds; + if (now.Nanosec < first.Nanosec) { + seconds--; + milliSeconds = 1000-(first.Nanosec-now.Nanosec)/1000000; + } + else + milliSeconds = (now.Nanosec-first.Nanosec)/1000000; + char relativeTimestamp[100]; + sprintf(relativeTimestamp, "%d.%03d", seconds, milliSeconds); + s << relativeTimestamp << ':'; + break; + } // case OutputItem::RELATIVETIMER + + case OutputItem::SYSTEMTICKS: + s << osl_getSystemTicks() << ':'; + break; + + default: + return; + } + } +} + +#endif + +void parseLogEnvironment() +{ + if (bParsedLogEnvironment) + return; + osl::MutexGuard aGuard( aParserMutex ); + if (bParsedLogEnvironment) + return; + bParsedLogEnvironment = true; char const * env = getEnvironmentVariable(); - if (env == nullptr) + if (nullptr == env) return; - bool outputTimestamp = false; - bool outputRelativeTimer = false; - for (char const * p = env;;) { - switch (*p++) { + unsigned int nOutputItem = 0; + bool aOutputSeenList[ OutputItem::LAST ] = { false, }; + for (char const * p = env;;) + { + switch (*p++) + { case '\0': - if (outputTimestamp) { - char ts[100]; - TimeValue systemTime; - osl_getSystemTime(&systemTime); - TimeValue localTime; - osl_getLocalTimeFromSystemTime(&systemTime, &localTime); - oslDateTime dateTime; - osl_getDateTimeFromTimeValue(&localTime, &dateTime); - struct tm tm; - tm.tm_sec = dateTime.Seconds; - tm.tm_min = dateTime.Minutes; - tm.tm_hour = dateTime.Hours; - tm.tm_mday = dateTime.Day; - tm.tm_mon = dateTime.Month - 1; - tm.tm_year = dateTime.Year - 1900; - strftime(ts, sizeof(ts), "%Y-%m-%d:%H:%M:%S", &tm); - char milliSecs[11]; - sprintf(milliSecs, "%03u", static_cast<unsigned>(dateTime.NanoSeconds/1000000)); - s << ts << '.' << milliSecs << ':'; + break; + case '+': + { + char const * p1 = p; + while (*p1 != '.' && *p1 != '+' && *p1 != '-' && *p1 != '\0') { + ++p1; } - if (outputRelativeTimer) { - static bool beenHere = false; - static TimeValue first; - if (!beenHere) { - osl_getSystemTime(&first); - beenHere = true; - } - TimeValue now; - osl_getSystemTime(&now); - int seconds = now.Seconds - first.Seconds; - int milliSeconds; - if (now.Nanosec < first.Nanosec) { - seconds--; - milliSeconds = 1000-(first.Nanosec-now.Nanosec)/1000000; - } - else - milliSeconds = (now.Nanosec-first.Nanosec)/1000000; - char relativeTimestamp[100]; - sprintf(relativeTimestamp, "%d.%03d", seconds, milliSeconds); - s << relativeTimestamp << ':'; + if (!aOutputSeenList[ OutputItem::TIMESTAMP ] + && equalStrings(p, p1 - p, RTL_CONSTASCII_STRINGPARAM("TIMESTAMP"))) + { + aOutputSeenList[ OutputItem::TIMESTAMP ] = true; + aOutputList[ nOutputItem++ ] = OutputItem::TIMESTAMP; } - return; - case '+': + else if (!aOutputSeenList[ OutputItem::RELATIVETIMER ] + && equalStrings(p, p1 - p, RTL_CONSTASCII_STRINGPARAM("RELATIVETIMER"))) { - char const * p1 = p; - while (*p1 != '.' && *p1 != '+' && *p1 != '-' && *p1 != '\0') { - ++p1; - } - if (equalStrings(p, p1 - p, RTL_CONSTASCII_STRINGPARAM("TIMESTAMP"))) - outputTimestamp = true; - else if (equalStrings(p, p1 - p, RTL_CONSTASCII_STRINGPARAM("RELATIVETIMER"))) - outputRelativeTimer = true; - char const * p2 = p1; - while (*p2 != '+' && *p2 != '-' && *p2 != '\0') { - ++p2; - } - p = p2; + aOutputSeenList[ OutputItem::RELATIVETIMER ] = true; + aOutputList[ nOutputItem++ ] = OutputItem::RELATIVETIMER; } + else if (!aOutputSeenList[ OutputItem::SYSTEMTICKS ] + && equalStrings(p, p1 - p, RTL_CONSTASCII_STRINGPARAM("SYSTEMTICKS"))) + { + aOutputSeenList[ OutputItem::SYSTEMTICKS ] = true; + aOutputList[ nOutputItem++ ] = OutputItem::SYSTEMTICKS; + } + char const * p2 = p1; + while (*p2 != '+' && *p2 != '-' && *p2 != '\0') { + ++p2; + } + p = p2; break; + } // case '+' + default: - ; // nothing + break; // nothing } } } -#endif - -} +} // anonymous namespace void sal_detail_log( sal_detail_LogLevel level, char const * area, char const * where, char const * message, sal_uInt32 backtraceDepth) { + parseLogEnvironment(); std::ostringstream s; #if !defined ANDROID // On Android, the area will be used as the "tag," and log info already commit e4b932feb197580831cc099f2f76c5049cb19edc Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 15 23:22:36 2017 +0200 Move tools::time::getSystemTicks() into osl Moves the code into osl_getSystemTicks and marks the original funtion as deprecated. Also merges a duplicate W32 implementation. Change-Id: I5c9263540b8af55b2eeca6126e288129427f6e8e diff --git a/canvas/source/tools/elapsedtime.cxx b/canvas/source/tools/elapsedtime.cxx index e82df7dbe3fb..fc5d7f9967d9 100644 --- a/canvas/source/tools/elapsedtime.cxx +++ b/canvas/source/tools/elapsedtime.cxx @@ -48,57 +48,6 @@ namespace canvas { namespace tools { - -#if defined(_WIN32) -// TODO(Q2): is 0 okay for the failure case here? -double ElapsedTime::getSystemTime() -{ - // TEMP!!! - // Awaiting corresponding functionality in OSL - - - // is there a performance counter available? - static bool bTimeSetupDone( false ); - static bool bPerfTimerAvailable( false ); - static LONGLONG nPerfCountFreq; - - // TODO(F1): This _might_ cause problems, as it prevents correct - // time handling for very long lifetimes of this class's - // surrounding component in memory. When the difference between - // current sys time and nInitialCount exceeds IEEE double's - // mantissa, time will start to run jerky. - static LONGLONG nInitialCount; - - if( !bTimeSetupDone ) - { - if( QueryPerformanceFrequency( - reinterpret_cast<LARGE_INTEGER *>(&nPerfCountFreq) ) ) - { - // read initial time: - QueryPerformanceCounter( - reinterpret_cast<LARGE_INTEGER *>(&nInitialCount) ); - bPerfTimerAvailable = true; - } - bTimeSetupDone = true; - } - - if( bPerfTimerAvailable ) - { - LONGLONG nCurrCount; - QueryPerformanceCounter( - reinterpret_cast<LARGE_INTEGER *>(&nCurrCount) ); - nCurrCount -= nInitialCount; - return double(nCurrCount) / nPerfCountFreq; - } - else - { - LONGLONG nCurrTime = timeGetTime(); - return double(nCurrTime) / 1000.0; - } -} - -#else // ! WNT - // TODO(Q2): is 0 okay for the failure case here? double ElapsedTime::getSystemTime() { @@ -109,8 +58,6 @@ double ElapsedTime::getSystemTime() return 0.0; } -#endif - ElapsedTime::ElapsedTime() : m_pTimeBase(), m_fLastQueriedTime( 0.0 ), diff --git a/include/osl/time.h b/include/osl/time.h index 4843a9d02e25..b263ea1735d8 100644 --- a/include/osl/time.h +++ b/include/osl/time.h @@ -167,11 +167,16 @@ SAL_DLLPUBLIC sal_Bool SAL_CALL osl_getSystemTimeFromLocalTime( /** Get the value of the global timer - @return current timer value in milli seconds + @return current timer value in milliseconds */ - SAL_DLLPUBLIC sal_uInt32 SAL_CALL osl_getGlobalTimer(void); + +/** Get the elapsed time since epoch in milliseconds + @return current system ticks + */ +SAL_DLLPUBLIC sal_uInt64 SAL_CALL osl_getSystemTicks(void); + #ifdef __cplusplus } #endif diff --git a/include/tools/time.hxx b/include/tools/time.hxx index d8b4e6d06fc6..77d2d12dbea4 100644 --- a/include/tools/time.hxx +++ b/include/tools/time.hxx @@ -121,7 +121,9 @@ public: static Time GetUTCOffset(); - /// Elapsed time since epoch in milliseconds + /** Elapsed time since epoch in milliseconds + * @deprecated use osl_getSystemTicks + */ static sal_uInt64 GetSystemTicks(); tools::Time& operator =( const tools::Time& rTime ); diff --git a/sal/osl/unx/time.cxx b/sal/osl/unx/time.cxx index 61d452434d64..ca567ed3f0a5 100644 --- a/sal/osl/unx/time.cxx +++ b/sal/osl/unx/time.cxx @@ -308,4 +308,16 @@ sal_uInt32 SAL_CALL osl_getGlobalTimer() return nSeconds; } +sal_uInt64 SAL_CALL osl_getSystemTicks() +{ + timeval tv; + int n = gettimeofday (&tv, nullptr); + if (n == -1) { + fprintf(stderr, "gettimeofday failed: %i\n", errno); + abort(); + } + return static_cast<sal_uInt64>(tv.tv_sec) * 1000 + + static_cast<sal_uInt64>(tv.tv_usec) / 1000; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/osl/w32/time.cxx b/sal/osl/w32/time.cxx index 1a6e6ceaa181..d1f1961b3ac6 100644 --- a/sal/osl/w32/time.cxx +++ b/sal/osl/w32/time.cxx @@ -200,4 +200,30 @@ sal_uInt32 SAL_CALL osl_getGlobalTimer(void) return ( nSeconds * 1000 ) + (long)( currentTime.millitm - startTime.millitm ); } +sal_uInt64 SAL_CALL osl_getSystemTicks(void) +{ + static LARGE_INTEGER nTicksPerSecond = 0; + static bool bTicksPerSecondInitialized = false; + + if (!bTicksPerSecondInitialized) + { + bTicksPerSecondInitialized = true; + if (!QueryPerformanceFrequency(&nTicksPerSecond)) + nTicksPerSecond = 0; + } + + if (nTicksPerSecond > 0) + { + LARGE_INTEGER nPerformanceCount; + QueryPerformanceCounter(&nPerformanceCount); + return static_cast<sal_uInt64>( + (nPerformanceCount.QuadPart*1000)/nTicksPerSecond.QuadPart); + } + else + { + LONGLONG nCurrTime = timeGetTime(); + return double(nCurrTime) / 1000.0; + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sal/util/sal.map b/sal/util/sal.map index e9195a1434f8..04d3bf4e8baf 100644 --- a/sal/util/sal.map +++ b/sal/util/sal.map @@ -707,6 +707,11 @@ LIBO_UDK_5.3 { # symbols available in >= LibO 5.3 rtl_uString_newReplaceFirstUtf16LUtf16L; } LIBO_UDK_5.2; +LIBO_UDK_6_0 { # symbols available in >= LibO 6.0 + global: + osl_getSystemTicks; +} LIBO_UDK_5.3; + PRIVATE_1.0 { global: osl_detail_ObjectRegistry_storeAddresses; diff --git a/tools/source/datetime/ttime.cxx b/tools/source/datetime/ttime.cxx index 83812f72171a..32ec7a150cf4 100644 --- a/tools/source/datetime/ttime.cxx +++ b/tools/source/datetime/ttime.cxx @@ -39,6 +39,7 @@ #include <sal/log.hxx> #include <tools/time.hxx> #include <osl/diagnose.h> +#include <osl/time.h> #if defined(__sun) && defined(__GNUC__) extern long altzone; @@ -411,30 +412,7 @@ Time tools::Time::GetUTCOffset() sal_uInt64 tools::Time::GetSystemTicks() { -#if defined(_WIN32) - static LARGE_INTEGER nTicksPerSecond; - static bool bTicksPerSecondInitialized = false; - if (!bTicksPerSecondInitialized) - { - QueryPerformanceFrequency(&nTicksPerSecond); - bTicksPerSecondInitialized = true; - } - - LARGE_INTEGER nPerformanceCount; - QueryPerformanceCounter(&nPerformanceCount); - - return static_cast<sal_uInt64>( - (nPerformanceCount.QuadPart*1000)/nTicksPerSecond.QuadPart); -#else - timeval tv; - int n = gettimeofday (&tv, nullptr); - if (n == -1) { - int e = errno; - SAL_WARN("tools.datetime", "gettimeofday failed: " << e); - } - return static_cast<sal_uInt64>(tv.tv_sec) * 1000 - + static_cast<sal_uInt64>(tv.tv_usec) / 1000; -#endif + return osl_getSystemTicks(); } } /* namespace tools */ commit a441c264b1a9fe245cd3db5c7f6bac526df6d0a6 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 15 09:03:49 2017 +0200 Abort on critical Scheduler problems There is not much sense in trying to continue without the main lock. An other aspect are tasks with uncaught exceptions, which must not happen. In both cases simply abort. Change-Id: I4d52a6ef0526a1e46b64f9f3a6e0cc1a718618cc diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx index 50a45006ced1..4187af3f3e8b 100644 --- a/vcl/source/app/scheduler.cxx +++ b/vcl/source/app/scheduler.cxx @@ -28,6 +28,7 @@ #include <saltimer.hxx> #include <salinst.hxx> #include <comphelper/profilezone.hxx> +#include <tools/diagnose_ex.h> #include <schedulerimpl.hxx> namespace { @@ -155,20 +156,22 @@ void Scheduler::ImplDeInitScheduler() void SchedulerMutex::acquire( sal_uInt32 nLockCount ) { + assert(nLockCount > 0); for (sal_uInt32 i = 0; i != nLockCount; ++i) { - bool ok = maMutex.acquire(); - assert(ok); (void) ok; - ++mnLockDepth; + if (!maMutex.acquire()) + abort(); } + mnLockDepth += nLockCount; } sal_uInt32 SchedulerMutex::release( bool bUnlockAll ) { - assert(mnLockDepth != 0); + assert(mnLockDepth > 0); sal_uInt32 nLockCount = bUnlockAll ? mnLockDepth : 1; mnLockDepth -= nLockCount; for (sal_uInt32 i = 0; i != nLockCount; ++i) { - maMutex.release(); + if (!maMutex.release()) + abort(); } return nLockCount; } @@ -404,7 +407,17 @@ next_entry: // not run a nested Scheduler loop and don't need a stack push! pMostUrgent->mbInScheduler = true; sal_uInt32 nLockCount = Unlock( true ); - pTask->Invoke(); + try + { + pTask->Invoke(); + } + catch (...) + { + SAL_WARN( "vcl.schedule", + "Uncaught exception during Task::Invoke()!" ); + DBG_UNHANDLED_EXCEPTION(); + abort(); + } Lock( nLockCount ); pMostUrgent->mbInScheduler = false; commit 6cba8a3b54f0176f0f020d28cc24f318ae1aa9b5 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 15 09:02:16 2017 +0200 SVP always drain the wakeup pipe Even when we have a lot of idle events, the pipe gets filled, so just drain it on every run. Change-Id: I7b6366b2649133b63138dc77fe51508404132890 diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx index 4b76f0c3fbec..4ebeac8f4a3c 100644 --- a/vcl/headless/svpinst.cxx +++ b/vcl/headless/svpinst.cxx @@ -370,6 +370,12 @@ bool SvpSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLong DoReleaseYield(nTimeoutMS); } + else if ( bEvent ) + { + // Drain the wakeup pipe + int buffer; + while (read (m_pTimeoutFDS[0], &buffer, sizeof(buffer)) > 0); + } return bEvent; } @@ -394,8 +400,7 @@ void SvpSalInstance::DoReleaseYield( int nTimeoutMS ) if( (aPoll.revents & POLLIN) != 0 ) { int buffer; - while (read (m_pTimeoutFDS[0], &buffer, sizeof(buffer)) > 0) - continue; + while (read (m_pTimeoutFDS[0], &buffer, sizeof(buffer)) > 0); } } commit 08fe60dedd520d9301e444a6074ec421c1d7e3d7 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 15 09:19:37 2017 +0200 tdf#99784 update Scheduler documentation Reflect special handling in the OSX backend. Change-Id: I6493ba6b6cf1c69f9fafc7ab583c430d72f73247 diff --git a/vcl/README.scheduler b/vcl/README.scheduler index 1f2d617734a0..80435c3a2468 100644 --- a/vcl/README.scheduler +++ b/vcl/README.scheduler @@ -91,13 +91,26 @@ can be added to the scheduler reasonably. == MacOS implementation details == -Generally the Scheduler is handled as expected. There is a workaround for a -problem for pushing tasks to an empty queue, as [NSApp postEvent: ... -atStart: NO] doesn't append the event, if the message queue is empty. +Generally the Scheduler is handled as expected, except on resize, which is +handled with different runloop-modes in MacOS. +In case of a resize, the normal runloop is suspended in sendEvent, so we +can't call the scheduler via posted main loop-events. + +Like the Windows backend, all Cocoa / GUI handling also has to be done in +the main thread. But unless Windows out-of-order PeekMessage processing, +via MsgWaitForMultipleObjects, we have to rely on a wakeup message, if +the SolarMutex is unlocked. + +There is also a workaround for a problem for pushing tasks to an empty queue, +as [NSApp postEvent: ... atStart: NO] doesn't append the event, if the +message queue is empty. Probably that's the reason, why some code comments spoke of lost events and there was some distinct additional event processing implemented. +OTOH we can use a closure like feature to execute the GUI code block in the +main thread, without much hazzle. + == Windows implementation details == Posted or sent event messages often trigger processing of WndProc in @@ -154,3 +167,8 @@ easy way to process just a single event). Since the Scheduler is always handled by the system message queue, there is really no more reasoning to stop after 100 events to prevent LO Scheduler starvation. + +== Run the LO application in it's own thread == + +Thi swould probably get rid of most of the MacOS and Windows implementation +details / workarounds. But this seems to be even more work to do. commit 10280666929a493a0df10e90dcf5ed39a9ab36fd Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 15 08:23:31 2017 +0200 tdf#99784 OSX fix painting on resize While resizing MacOS suspends the NSDefaultRunLoopMode. So in this caae we can't post to the system event loop, but must use timers to restart ourself. Since the timer itself is scheduled on the NSEventTrackingRunLoopMode it' also triggers on resize events. There is still some minor glitch: when resizing too fast some part of LibreOffice isn't painted, while the left mouse button is down. Since there isn't any layouting triggered by the mouse up, there has to be an other inconsistency. Change-Id: I3ccba78bd23ec8526f21e7b93b027f3d3279f901 diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h index 0dabc93c069c..d9e79e0134d6 100644 --- a/vcl/inc/osx/salinst.h +++ b/vcl/inc/osx/salinst.h @@ -78,6 +78,7 @@ public: osl::Mutex maUserEventListMutex; osl::Condition maWaitingYieldCond; bool mbNoNotificationLock; + bool mbIsLiveResize; static std::list<const ApplicationEvent*> aAppEventList; diff --git a/vcl/osx/salframeview.mm b/vcl/osx/salframeview.mm index fb78b39b1833..99b48b2ee439 100644 --- a/vcl/osx/salframeview.mm +++ b/vcl/osx/salframeview.mm @@ -541,6 +541,17 @@ private: -(void)drawRect: (NSRect)aRect { + if( GetSalData()->mpFirstInstance ) + { + const bool bIsLiveResize = [self inLiveResize]; + const bool bWasLiveResize = GetSalData()->mpFirstInstance->mbIsLiveResize; + if ( bWasLiveResize != bIsLiveResize ) + { + GetSalData()->mpFirstInstance->mbIsLiveResize = bIsLiveResize; + Scheduler::ProcessTaskScheduling(); + } + } + // HOTFIX: #i93512# prevent deadlocks if any other thread already has the SalYieldMutex TryGuard aTryGuard; if( !aTryGuard.IsGuarded() ) diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index f68d4031e3d8..b0abc96a205a 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -350,6 +350,7 @@ AquaSalInstance::AquaSalInstance() : maUserEventListMutex() , maWaitingYieldCond() , mbNoNotificationLock( false ) + , mbIsLiveResize( false ) { mpSalYieldMutex = new SalYieldMutex; mpSalYieldMutex->acquire(); diff --git a/vcl/osx/salnstimer.mm b/vcl/osx/salnstimer.mm index c9867cf7a79e..c9b657dcd776 100644 --- a/vcl/osx/salnstimer.mm +++ b/vcl/osx/salnstimer.mm @@ -30,7 +30,13 @@ -(void)timerElapsed:(NSTimer*)pTimer { (void)pTimer; - ImplNSAppPostEvent( AquaSalInstance::DispatchTimerEvent, YES ); + // nil the timer, as it is just invalidated after the firing function + AquaSalTimer::pRunningTimer = nil; + const AquaSalInstance *pInst = GetSalData()->mpFirstInstance; + if (pInst->mbIsLiveResize) + AquaSalTimer::handleDispatchTimerEvent(); + else + ImplNSAppPostEvent( AquaSalInstance::DispatchTimerEvent, YES ); } @end diff --git a/vcl/osx/saltimer.cxx b/vcl/osx/saltimer.cxx index 62814759ae1a..23aa0f583707 100644 --- a/vcl/osx/saltimer.cxx +++ b/vcl/osx/saltimer.cxx @@ -83,7 +83,7 @@ static void ImplSalStartTimer( sal_uLong nMS ) return; } - if ( 0 == nMS ) + if ( 0 == nMS && !pSalData->mpFirstInstance->mbIsLiveResize ) { ImplSalStopTimer(); ImplNSAppPostEvent( AquaSalInstance::DispatchTimerEvent, NO ); @@ -93,7 +93,7 @@ static void ImplSalStartTimer( sal_uLong nMS ) NSTimeInterval aTI = double(nMS) / 1000.0; if( AquaSalTimer::pRunningTimer != nil ) { - if (rtl::math::approxEqual( + if ([AquaSalTimer::pRunningTimer isValid] && rtl::math::approxEqual( [AquaSalTimer::pRunningTimer timeInterval], aTI)) { // set new fire date commit ea1b4b274e738faef45087afa220884955c7ad0b Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 8 15:03:37 2017 +0200 tdf#99784 OSX run GUI stuff in the main thread The extension manager start dialogs from it's own thread. But the OSX backend currently doesn't defer these calls to the main thread. This implements the deference using dispatch_sync. Since dispatch_sync can't return any values, we have to use a thread-id based map to transfer the return values from the main thread to the callers. The implementation uses macros, so it can rely on guard objects. Change-Id: Id8977991e3eda91da27c23d8021e028d4f4cefe5 diff --git a/include/vcl/pointr.hxx b/include/vcl/pointr.hxx index c82fb2236db0..8370b9f9d296 100644 --- a/include/vcl/pointr.hxx +++ b/include/vcl/pointr.hxx @@ -23,8 +23,6 @@ #include <vcl/dllapi.h> #include <vcl/ptrstyle.hxx> -class Point; - class VCL_DLLPUBLIC Pointer { PointerStyle meStyle; diff --git a/vcl/inc/osx/runinmain.hxx b/vcl/inc/osx/runinmain.hxx new file mode 100644 index 000000000000..5df04b052a05 --- /dev/null +++ b/vcl/inc/osx/runinmain.hxx @@ -0,0 +1,134 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_RUNINMAIN_HXX +#define INCLUDED_VCL_INC_OSX_RUNINMAIN_HXX + +/** + * Runs a single line command in the main thread. + * + * This is currently always used like a "recursive" call. + * These macros are most times intended to work as a closure, + * + * As dispatch_sync doesn't support any return values, we have to use a + * global map with thread-id keys. The map is protected by the SolarMutex + * and is a member of the SalData object. + * + * The types are constructed in osx/runinmain_type.hxx. + * + * There are three main macros, which act as function initializers: + * - OSX_RUNINMAIN - for all functions without return values + * - OSX_RUNINMAIN_POINTER - for all functions returning a pointer + * - OSX_RUNINMAIN_UNION - for all other return types + * + * All types used via OSX_RUNINMAIN_UNION must implement a move constructor, + * so there is no memory leak! + */ + +#include "osx/runinmain_type.hxx" + +#define OSX_RUNINMAIN( dispatcher, instance, command ) \ + if ( !instance->IsMainThread() ) \ + { \ + dispatcher(dispatch_get_main_queue(), ^{ \ + assert( !instance->mbNoNotificationLock ); \ + instance->mbNoNotificationLock = true; \ + command; \ + instance->mbNoNotificationLock = false; \ + }); \ + return; \ + } + +#define OSX_RUNINMAIN_POINTER( instance, command, type ) \ + if ( !instance->IsMainThread() ) \ + { \ + OSXRuninmainResultMap &rResultMap = GetSalData()->maResultMap; \ + oslThreadIdentifier aThreadId = osl::Thread::getCurrentIdentifier(); \ + { \ + dispatch_sync(dispatch_get_main_queue(), ^{ \ + assert( !instance->mbNoNotificationLock ); \ + instance->mbNoNotificationLock = true; \ + rResultMap[ aThreadId ].pointer = static_cast<void*>( command ); \ + instance->mbNoNotificationLock = false; \ + }); \ + } \ + auto aResultIter = rResultMap.find( aThreadId ); \ + assert( aResultIter != rResultMap.end() ); \ + auto aResult = static_cast<type>( aResultIter->second.pointer ); \ + rResultMap.erase( aResultIter ); \ + return aResult; \ + } + +#define OSX_RUNINMAIN_UNION( instance, command, member ) \ + if ( !instance->IsMainThread() ) \ + { \ + OSXRuninmainResultMap &rResultMap = GetSalData()->maResultMap; \ + oslThreadIdentifier aThreadId = osl::Thread::getCurrentIdentifier(); \ + { \ + dispatch_sync(dispatch_get_main_queue(), ^{ \ + assert( !instance->mbNoNotificationLock ); \ + instance->mbNoNotificationLock = true; \ + rResultMap[ aThreadId ].member = command; \ + instance->mbNoNotificationLock = false; \ + }); \ + } \ + auto aResultIter = rResultMap.find( aThreadId ); \ + assert( aResultIter != rResultMap.end() ); \ + auto aResult = std::move( aResultIter->second.member ); \ + rResultMap.erase( aResultIter ); \ + return aResult; \ + } + +/** + * convenience macros used from SalInstance + */ + +#define OSX_INST_RUNINMAIN( command ) \ + OSX_RUNINMAIN( dispatch_sync, this, command ) + +#define OSX_INST_RUNINMAIN_ASYNC( command ) \ + OSX_RUNINMAIN( dispatch_async, this, command ) \ + osl::Guard< comphelper::SolarMutex > aGuard( *mpSalYieldMutex ); + +#define OSX_INST_RUNINMAIN_POINTER( command, type ) \ + OSX_RUNINMAIN_POINTER( this, command, type ) + +#define OSX_INST_RUNINMAIN_UNION( command, member ) \ + OSX_RUNINMAIN_UNION( this, command, member ) + +/** + * convenience macros useing global SalData + */ + +#define OSX_SALDATA_RUNINMAIN( command ) \ + OSX_RUNINMAIN( dispatch_sync, GetSalData()->mpFirstInstance, command ) + +#define OSX_SALDATA_RUNINMAIN_ASYNC( command ) \ + OSX_RUNINMAIN( dispatch_async, GetSalData()->mpFirstInstance, command ) \ + osl::Guard< comphelper::SolarMutex > aGuard( *GetSalData()->mpFirstInstance->mpSalYieldMutex ); + +#define OSX_SALDATA_RUNINMAIN_POINTER( command, type ) \ + OSX_RUNINMAIN_POINTER( GetSalData()->mpFirstInstance, command, type ) + +#define OSX_SALDATA_RUNINMAIN_UNION( command, member ) \ + OSX_RUNINMAIN_UNION( GetSalData()->mpFirstInstance, command, member ) + +#endif // INCLUDED_VCL_INC_OSX_RUNINMAIN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/runinmain_type.hxx b/vcl/inc/osx/runinmain_type.hxx new file mode 100644 index 000000000000..7f946fb28bde --- /dev/null +++ b/vcl/inc/osx/runinmain_type.hxx @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_RUNINMAIN_TYPE_HXX +#define INCLUDED_VCL_INC_OSX_RUNINMAIN_TYPE_HXX + +/** + * For more information look into runinmain.hxx. + */ + +#include <osl/thread.h> +#include <unordered_map> +#include "salframe.hxx" + +union RuninmainResult +{ + void* pointer; + bool boolean; + struct SalFrame::SalPointerState state; + + RuninmainResult() {} +}; + +typedef std::unordered_map<oslThreadIdentifier, RuninmainResult> OSXRuninmainResultMap; + +#define OSX_RUNINMAIN_RESULTS \ + OSXRuninmainResultMap maResultMap; + +#endif // INCLUDED_VCL_INC_OSX_RUNINMAIN_TYPE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/saldata.hxx b/vcl/inc/osx/saldata.hxx index fbc28e05391d..8c590f304679 100644 --- a/vcl/inc/osx/saldata.hxx +++ b/vcl/inc/osx/saldata.hxx @@ -45,6 +45,8 @@ #include "apple_remote/RemoteMainController.h" +#include "osx/runinmain_type.hxx" + class AquaSalInstance; class SalObject; class SalFrame; @@ -107,6 +109,8 @@ public: static void ensureThreadAutoreleasePool(); static NSStatusItem* getStatusItem(); + + OSX_RUNINMAIN_RESULTS; }; inline void SetSalData( SalData* pData ) { ImplGetSVData()->mpSalData = pData; } diff --git a/vcl/inc/osx/salframe.h b/vcl/inc/osx/salframe.h index 4b6d486f6be6..307356c76caa 100644 --- a/vcl/inc/osx/salframe.h +++ b/vcl/inc/osx/salframe.h @@ -29,6 +29,7 @@ #include "osx/salmenu.h" #include "osx/saldata.hxx" #include "osx/osxvcltypes.h" +#include "osx/runinmain.hxx" #include "salframe.hxx" @@ -183,22 +184,22 @@ public: void VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen = true ); void CocoaToVCL( NSPoint& io_Point, bool bRelativeToScreen = true ); - NSCursor* getCurrentCursor() const; + NSCursor* getCurrentCursor(); CGMutablePathRef getClipPath() const { return mrClippingPath; } // called by VCL_NSApplication to indicate screen settings have changed void screenParametersChanged(); - private: // methods +private: // methods /** do things on initial show (like centering on parent or on screen) */ void initShow(); void initWindowAndView(); - private: // data - static AquaSalFrame* s_pCaptureFrame; +private: // data + static AquaSalFrame* s_pCaptureFrame; AquaSalFrame( const AquaSalFrame& ) = delete; AquaSalFrame& operator=(const AquaSalFrame&) = delete; diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h index f47ae7cc8303..0dabc93c069c 100644 --- a/vcl/inc/osx/salinst.h +++ b/vcl/inc/osx/salinst.h @@ -32,7 +32,11 @@ #endif #include "salinst.hxx" +#include "osx/runinmain.hxx" + class AquaSalFrame; +class SalFrame; +class SalObject; class ApplicationEvent; class Image; enum class SalEvent; @@ -73,9 +77,12 @@ public: std::list< SalUserEvent > maUserEvents; osl::Mutex maUserEventListMutex; osl::Condition maWaitingYieldCond; + bool mbNoNotificationLock; static std::list<const ApplicationEvent*> aAppEventList; + OSX_RUNINMAIN_RESULTS; + public: AquaSalInstance(); virtual ~AquaSalInstance() override; @@ -151,6 +158,7 @@ public: static const short AppStartTimerEvent = 10; static const short PostedUserEvent = 20; static const short DispatchTimerEvent = 30; + static const short UnlockedYieldMutexEvent = 40; static NSMenu* GetDynamicDockMenu(); }; diff --git a/vcl/osx/a11ytextwrapper.mm b/vcl/osx/a11ytextwrapper.mm index a46ffd6e7fd9..14a63aa8fd9e 100644 --- a/vcl/osx/a11ytextwrapper.mm +++ b/vcl/osx/a11ytextwrapper.mm @@ -203,8 +203,8 @@ using namespace ::com::sun::star::uno; +(id)rangeForPositionAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)point { NSValue * value = nil; - Point aPoint( [ AquaA11yUtil nsPointToVclPoint: point ]); - const Point screenPos = [ wrapper accessibleComponent ] -> getLocationOnScreen(); + css::awt::Point aPoint( [ AquaA11yUtil nsPointToVclPoint: point ]); + const css::awt::Point screenPos = [ wrapper accessibleComponent ] -> getLocationOnScreen(); aPoint.X -= screenPos.X; aPoint.Y -= screenPos.Y; sal_Int32 index = [ wrapper accessibleText ] -> getIndexAtPoint( aPoint ); @@ -239,9 +239,9 @@ using namespace ::com::sun::star::uno; } if ( [ wrapper accessibleComponent ] ) { // get location on screen (must be added since get CharacterBounds returns values relative to parent) - Point screenPos = [ wrapper accessibleComponent ] -> getLocationOnScreen(); - Point pos ( minx + screenPos.X, miny + screenPos.Y ); - Point size ( maxx - minx, maxy - miny ); + css::awt::Point screenPos = [ wrapper accessibleComponent ] -> getLocationOnScreen(); + css::awt::Point pos ( minx + screenPos.X, miny + screenPos.Y ); + css::awt::Point size ( maxx - minx, maxy - miny ); NSValue * nsPos = [ AquaA11yUtil vclPointToNSPoint: pos ]; rect = [ NSValue valueWithRect: NSMakeRect ( [ nsPos pointValue ].x, [ nsPos pointValue ].y - size.Y, size.X, size.Y ) ]; //printf("Range: %s --- Rect: %s\n", [ NSStringFromRange ( [ range rangeValue ] ) UTF8String ], [ NSStringFromRect ( [ rect rectValue ] ) UTF8String ]); diff --git a/vcl/osx/salframe.cxx b/vcl/osx/salframe.cxx index a29eba5eb766..4d6c85299a9c 100644 --- a/vcl/osx/salframe.cxx +++ b/vcl/osx/salframe.cxx @@ -36,6 +36,7 @@ #include "osx/salinst.h" #include "osx/salframeview.h" #include "osx/a11yfactory.h" +#include "osx/runinmain.hxx" #include "quartz/utils.h" #include "salwtype.hxx" @@ -92,6 +93,8 @@ AquaSalFrame::AquaSalFrame( SalFrame* pParent, SalFrameStyleFlags salFrameStyle AquaSalFrame::~AquaSalFrame() { + assert( GetSalData()->mpFirstInstance->IsMainThread() ); + // if the frame is destroyed and has the current menubar // set the default menubar if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu ) @@ -134,6 +137,8 @@ AquaSalFrame::~AquaSalFrame() void AquaSalFrame::initWindowAndView() { + OSX_SALDATA_RUNINMAIN( initWindowAndView() ) + // initialize mirroring parameters // FIXME: screens changing NSScreen* pNSScreen = [mpNSWindow screen]; @@ -259,6 +264,8 @@ void AquaSalFrame::VCLToCocoa( NSPoint& io_rPoint, bool bRelativeToScreen ) void AquaSalFrame::screenParametersChanged() { + OSX_SALDATA_RUNINMAIN( screenParametersChanged() ) + UpdateFrameGeometry(); if( mpGraphics ) @@ -298,6 +305,8 @@ void AquaSalFrame::SetTitle(const OUString& rTitle) if ( !mpNSWindow ) return; + OSX_SALDATA_RUNINMAIN( SetTitle(rTitle) ) + // #i113170# may not be the main thread if called from UNO API SalData::ensureThreadAutoreleasePool(); @@ -342,8 +351,7 @@ void AquaSalFrame::SetIcon( sal_uInt16 ) void AquaSalFrame::SetRepresentedURL( const OUString& i_rDocURL ) { - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( SetRepresentedURL( i_rDocURL ) ) if( comphelper::isFileUrl(i_rDocURL) ) { @@ -360,6 +368,8 @@ void AquaSalFrame::SetRepresentedURL( const OUString& i_rDocURL ) void AquaSalFrame::initShow() { + OSX_SALDATA_RUNINMAIN( initShow() ) + mbInitShow = false; if( ! mbPositioned && ! mbFullScreen ) { @@ -397,6 +407,8 @@ void AquaSalFrame::initShow() void AquaSalFrame::SendPaintEvent( const tools::Rectangle* pRect ) { + OSX_SALDATA_RUNINMAIN( SendPaintEvent( pRect ) ) + SalPaintEvent aPaintEvt( 0, 0, maGeometry.nWidth, maGeometry.nHeight, true ); if( pRect ) { @@ -414,8 +426,7 @@ void AquaSalFrame::Show(bool bVisible, bool bNoActivate) if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN_ASYNC( Show(bVisible, bNoActivate) ) mbShown = bVisible; if(bVisible) @@ -472,8 +483,7 @@ void AquaSalFrame::Show(bool bVisible, bool bNoActivate) void AquaSalFrame::SetMinClientSize( long nWidth, long nHeight ) { - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( SetMinClientSize( nWidth, nHeight ) ) mnMinWidth = nWidth; mnMinHeight = nHeight; @@ -495,8 +505,7 @@ void AquaSalFrame::SetMinClientSize( long nWidth, long nHeight ) void AquaSalFrame::SetMaxClientSize( long nWidth, long nHeight ) { - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( SetMaxClientSize( nWidth, nHeight ) ) mnMaxWidth = nWidth; mnMaxHeight = nHeight; @@ -536,46 +545,45 @@ void AquaSalFrame::GetClientSize( long& rWidth, long& rHeight ) void AquaSalFrame::SetWindowState( const SalFrameState* pState ) { - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( SetWindowState( pState ) ) if ( mpNSWindow ) { - // set normal state - NSRect aStateRect = [mpNSWindow frame]; - aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask]; - CocoaToVCL( aStateRect ); - if( pState->mnMask & WindowStateMask::X ) - aStateRect.origin.x = float(pState->mnX); - if( pState->mnMask & WindowStateMask::Y ) - aStateRect.origin.y = float(pState->mnY); - if( pState->mnMask & WindowStateMask::Width ) - aStateRect.size.width = float(pState->mnWidth); - if( pState->mnMask & WindowStateMask::Height ) - aStateRect.size.height = float(pState->mnHeight); - VCLToCocoa( aStateRect ); - aStateRect = [NSWindow frameRectForContentRect: aStateRect styleMask: mnStyleMask]; - - [mpNSWindow setFrame: aStateRect display: NO]; - if( pState->mnState == WindowStateState::Minimized ) - [mpNSWindow miniaturize: NSApp]; - else if( [mpNSWindow isMiniaturized] ) - [mpNSWindow deminiaturize: NSApp]; - - /* ZOOMED is not really maximized (actually it toggles between a user set size and - the program specified one), but comes closest since the default behavior is - "maximized" if the user did not intervene - */ - if( pState->mnState == WindowStateState::Maximized ) - { - if(! [mpNSWindow isZoomed]) - [mpNSWindow zoom: NSApp]; - } - else - { - if( [mpNSWindow isZoomed] ) - [mpNSWindow zoom: NSApp]; - } + // set normal state + NSRect aStateRect = [mpNSWindow frame]; + aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask]; + CocoaToVCL( aStateRect ); + if( pState->mnMask & WindowStateMask::X ) + aStateRect.origin.x = float(pState->mnX); + if( pState->mnMask & WindowStateMask::Y ) + aStateRect.origin.y = float(pState->mnY); + if( pState->mnMask & WindowStateMask::Width ) + aStateRect.size.width = float(pState->mnWidth); + if( pState->mnMask & WindowStateMask::Height ) + aStateRect.size.height = float(pState->mnHeight); + VCLToCocoa( aStateRect ); + aStateRect = [NSWindow frameRectForContentRect: aStateRect styleMask: mnStyleMask]; + + [mpNSWindow setFrame: aStateRect display: NO]; + if( pState->mnState == WindowStateState::Minimized ) + [mpNSWindow miniaturize: NSApp]; + else if( [mpNSWindow isMiniaturized] ) + [mpNSWindow deminiaturize: NSApp]; + + /* ZOOMED is not really maximized (actually it toggles between a user set size and + the program specified one), but comes closest since the default behavior is + "maximized" if the user did not intervene + */ + if( pState->mnState == WindowStateState::Maximized ) + { + if(! [mpNSWindow isZoomed]) + [mpNSWindow zoom: NSApp]; + } + else + { + if( [mpNSWindow isZoomed] ) + [mpNSWindow zoom: NSApp]; + } } // get new geometry @@ -612,8 +620,7 @@ bool AquaSalFrame::GetWindowState( SalFrameState* pState ) if ( !mpNSWindow ) return FALSE; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN_UNION( GetWindowState( pState ), boolean ) pState->mnMask = WindowStateMask::X | WindowStateMask::Y | @@ -644,8 +651,7 @@ void AquaSalFrame::SetScreenNumber(unsigned int nScreen) if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( SetScreenNumber( nScreen ) ) NSArray* pScreens = [NSScreen screens]; NSScreen* pScreen = nil; @@ -682,14 +688,13 @@ void AquaSalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nDisplay ) if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); - SAL_INFO("vcl.osx", OSL_THIS_FUNC << ": mbFullScreen=" << mbFullScreen << ", bFullScreen=" << bFullScreen); if( mbFullScreen == bFullScreen ) return; + OSX_SALDATA_RUNINMAIN( ShowFullScreen( bFullScreen, nDisplay ) ) + mbFullScreen = bFullScreen; if( bFullScreen ) @@ -777,8 +782,7 @@ void AquaSalFrame::StartPresentation( bool bStart ) if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( StartPresentation( bStart ) ) if( bStart ) { @@ -808,8 +812,7 @@ void AquaSalFrame::ToTop(SalFrameToTop nFlags) if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( ToTop( nFlags ) ) if( ! (nFlags & SalFrameToTop::RestoreWhenMin) ) { @@ -822,8 +825,10 @@ void AquaSalFrame::ToTop(SalFrameToTop nFlags) [mpNSWindow orderFront: NSApp]; } -NSCursor* AquaSalFrame::getCurrentCursor() const +NSCursor* AquaSalFrame::getCurrentCursor() { + OSX_SALDATA_RUNINMAIN_POINTER( getCurrentCursor(), NSCursor* ) + NSCursor* pCursor = nil; switch( mePointerStyle ) { @@ -864,12 +869,11 @@ void AquaSalFrame::SetPointer( PointerStyle ePointerStyle ) { if ( !mpNSWindow ) return; - - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); - if( ePointerStyle == mePointerStyle ) return; + + OSX_SALDATA_RUNINMAIN( SetPointer( ePointerStyle ) ) + mePointerStyle = ePointerStyle; [mpNSWindow invalidateCursorRectsForView: mpNSView]; @@ -877,8 +881,9 @@ void AquaSalFrame::SetPointer( PointerStyle ePointerStyle ) void AquaSalFrame::SetPointerPos( long nX, long nY ) { - // FIXME: use Cocoa functions + OSX_SALDATA_RUNINMAIN( SetPointerPos( nX, nY ) ) + // FIXME: use Cocoa functions // FIXME: multiscreen support CGPoint aPoint = { static_cast<CGFloat>(nX + maGeometry.nX), static_cast<CGFloat>(nY + maGeometry.nY) }; CGDirectDisplayID mainDisplayID = CGMainDisplayID(); @@ -890,8 +895,7 @@ void AquaSalFrame::Flush() if( !(mbGraphics && mpGraphics && mpNSView && mbShown) ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( Flush() ) [mpNSView setNeedsDisplay: YES]; @@ -909,8 +913,7 @@ void AquaSalFrame::Flush( const tools::Rectangle& rRect ) if( !(mbGraphics && mpGraphics && mpNSView && mbShown) ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( Flush( rRect ) ) NSRect aNSRect = { { static_cast<CGFloat>(rRect.Left()), static_cast<CGFloat>(rRect.Top()) }, { static_cast<CGFloat>(rRect.GetWidth()), static_cast<CGFloat>(rRect.GetHeight()) } }; VCLToCocoa( aNSRect, false ); @@ -1118,6 +1121,8 @@ static vcl::Font getFont( NSFont* pFont, long nDPIY, const vcl::Font& rDefault ) void AquaSalFrame::getResolution( sal_Int32& o_rDPIX, sal_Int32& o_rDPIY ) { + OSX_SALDATA_RUNINMAIN( getResolution( o_rDPIX, o_rDPIY ) ) + if( ! mpGraphics ) { AcquireGraphics(); @@ -1137,8 +1142,7 @@ void AquaSalFrame::UpdateSettings( AllSettings& rSettings ) if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( UpdateSettings( rSettings ) ) [mpNSView lockFocus]; @@ -1242,6 +1246,7 @@ const SystemEnvData* AquaSalFrame::GetSystemData() const void AquaSalFrame::Beep() { + OSX_SALDATA_RUNINMAIN( Beep() ) NSBeep(); } @@ -1250,8 +1255,7 @@ void AquaSalFrame::SetPosSize(long nX, long nY, long nWidth, long nHeight, sal_u if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( SetPosSize( nX, nY, nWidth, nHeight, nFlags ) ) SalEvent nEvent = SalEvent::NONE; @@ -1340,8 +1344,7 @@ void AquaSalFrame::GetWorkArea( tools::Rectangle& rRect ) if ( !mpNSWindow ) return; - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( GetWorkArea( rRect ) ) NSScreen* pScreen = [mpNSWindow screen]; if( pScreen == nil ) @@ -1356,8 +1359,7 @@ void AquaSalFrame::GetWorkArea( tools::Rectangle& rRect ) SalPointerState AquaSalFrame::GetPointerState() { - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN_UNION( GetPointerState(), state ) SalPointerState state; state.mnState = 0; @@ -1492,8 +1494,7 @@ void AquaSalFrame::DrawMenuBar() void AquaSalFrame::SetMenu( SalMenu* pSalMenu ) { - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( SetMenu( pSalMenu ) ) AquaSalMenu* pMenu = static_cast<AquaSalMenu*>(pSalMenu); SAL_WARN_IF( pMenu && !pMenu->mbMenuBar, "vcl", "setting non menubar on frame" ); @@ -1504,14 +1505,16 @@ void AquaSalFrame::SetMenu( SalMenu* pSalMenu ) void AquaSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle ) { - if ( mpNSWindow ) + if ( !mpNSWindow ) { - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + mnExtStyle = nStyle; + return; + } + + OSX_SALDATA_RUNINMAIN( SetExtendedFrameStyle( nStyle ) ) if( (mnExtStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) != (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ) [mpNSWindow setDocumentEdited: (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ? YES : NO]; - } mnExtStyle = nStyle; } @@ -1534,9 +1537,9 @@ void AquaSalFrame::SetParent( SalFrame* pNewParent ) void AquaSalFrame::UpdateFrameGeometry() { if ( !mpNSWindow ) - { return; - } + + OSX_SALDATA_RUNINMAIN( UpdateFrameGeometry() ) // keep in mind that view and window coordinates are lower left // whereas vcl's are upper left @@ -1609,12 +1612,9 @@ void AquaSalFrame::CaptureMouse( bool bCapture ) void AquaSalFrame::ResetClipRegion() { if ( !mpNSWindow ) - { return; - } - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( ResetClipRegion() ) // release old path and indicate no clipping CGPathRelease( mrClippingPath ); @@ -1632,12 +1632,9 @@ void AquaSalFrame::ResetClipRegion() void AquaSalFrame::BeginSetClipRegion( sal_uLong nRects ) { if ( !mpNSWindow ) - { return; - } - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( BeginSetClipRegion( nRects ) ) // release old path if( mrClippingPath ) @@ -1671,12 +1668,9 @@ void AquaSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight void AquaSalFrame::EndSetClipRegion() { if ( !mpNSWindow ) - { return; - } - // #i113170# may not be the main thread if called from UNO API - SalData::ensureThreadAutoreleasePool(); + OSX_SALDATA_RUNINMAIN( EndSetClipRegion() ) if( ! maClippingRects.empty() ) { diff --git a/vcl/osx/salframeview.mm b/vcl/osx/salframeview.mm index e290891ce294..fb78b39b1833 100644 --- a/vcl/osx/salframeview.mm +++ b/vcl/osx/salframeview.mm @@ -223,13 +223,9 @@ static AquaSalFrame* getMouseContainerFrame() { if( GetSalData() && GetSalData()->mpFirstInstance ) { - comphelper::SolarMutex* pMutex = GetSalData()->mpFirstInstance->GetYieldMutex(); - if( pMutex ) - { - pMutex->acquire(); - [super displayIfNeeded]; - pMutex->release(); - } + GetSalData()->mpFirstInstance->AcquireYieldMutex( 1 ); + [super displayIfNeeded]; + GetSalData()->mpFirstInstance->ReleaseYieldMutex( false ); } } @@ -312,19 +308,28 @@ static AquaSalFrame* getMouseContainerFrame() -(void)windowDidMove: (NSNotification*)pNotification { (void)pNotification; - SolarMutexGuard aGuard; + + bool bNoLock = GetSalData()->mpFirstInstance->mbNoNotificationLock; + if ( !bNoLock ) + GetSalData()->mpFirstInstance->AcquireYieldMutex( 1 ); if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) { mpFrame->UpdateFrameGeometry(); mpFrame->CallCallback( SalEvent::Move, nullptr ); } + + if ( !bNoLock ) + GetSalData()->mpFirstInstance->ReleaseYieldMutex( false ); } -(void)windowDidResize: (NSNotification*)pNotification { (void)pNotification; - SolarMutexGuard aGuard; + + bool bNoLock = GetSalData()->mpFirstInstance->mbNoNotificationLock; + if ( !bNoLock ) + GetSalData()->mpFirstInstance->AcquireYieldMutex( 1 ); if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) { @@ -332,6 +337,9 @@ static AquaSalFrame* getMouseContainerFrame() mpFrame->CallCallback( SalEvent::Resize, nullptr ); mpFrame->SendPaintEvent(); } + + if ( !bNoLock ) + GetSalData()->mpFirstInstance->ReleaseYieldMutex( false ); } -(void)windowDidMiniaturize: (NSNotification*)pNotification diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index 45b7da6e36ee..f68d4031e3d8 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -46,6 +46,7 @@ #include "osx/salprn.h" #include "osx/saltimer.h" #include "osx/vclnsapp.h" +#include "osx/runinmain.hxx" #include "print.h" #include "impbmp.hxx" @@ -348,6 +349,7 @@ void DestroySalInstance( SalInstance* pInst ) AquaSalInstance::AquaSalInstance() : maUserEventListMutex() , maWaitingYieldCond() + , mbNoNotificationLock( false ) { mpSalYieldMutex = new SalYieldMutex; mpSalYieldMutex->acquire(); @@ -395,6 +397,10 @@ sal_uLong AquaSalInstance::ReleaseYieldMutex( bool bUnlockAll ) n--; } + if ( !IsMainThread() && (0 == nCurCount - nCount) ) + dispatch_async(dispatch_get_main_queue(),^{ + ImplNSAppPostEvent( AquaSalInstance::UnlockedYieldMutexEvent, NO ); + }); return nCount; } else @@ -404,6 +410,22 @@ sal_uLong AquaSalInstance::ReleaseYieldMutex( bool bUnlockAll ) void AquaSalInstance::AcquireYieldMutex( sal_uLong nCount ) { SalYieldMutex* pYieldMutex = mpSalYieldMutex; + + if ( nCount && IsMainThread() ) + { + while ( !mpSalYieldMutex->tryToAcquire() ) + { +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSAnyEventMask' is deprecated: first deprecated in macOS 10.12 + [NSApp nextEventMatchingMask: NSApplicationDefinedMask +SAL_WNODEPRECATED_DECLARATIONS_POP + untilDate: [NSDate distantFuture] + inMode: NSDefaultRunLoopMode + dequeue: NO]; + } + --nCount; + } + while ( nCount ) { pYieldMutex->acquire(); @@ -473,12 +495,16 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent ) // dispatch it if ( aEvent.mpFrame ) { - osl::Guard< comphelper::SolarMutex > aGuard( *mpSalYieldMutex ); + AcquireYieldMutex( 1 ); if ( AquaSalFrame::isAlive( aEvent.mpFrame ) ) aEvent.mpFrame->CallCallback( aEvent.mnType, aEvent.mpData ); + ReleaseYieldMutex( false ); } break; } + case UnlockedYieldMutexEvent: + // do nothing + break; #if !HAVE_FEATURE_MACOSX_SANDBOX case AppleRemoteControlEvent: // Defined in <apple_remote/RemoteMainController.h> { @@ -672,6 +698,8 @@ bool AquaSalInstance::AnyInput( VclInputFlags nType ) return false; } + OSX_INST_RUNINMAIN_UNION( AnyInput( nType ), boolean ) + if( nType & VclInputFlags::TIMER ) { if( AquaSalTimer::pRunningTimer ) @@ -684,9 +712,6 @@ bool AquaSalInstance::AnyInput( VclInputFlags nType ) } } - if (!IsMainThread()) - return false; - unsigned/*NSUInteger*/ nEventMask = 0; SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'NSFlagsChangedMask' is deprecated: first deprecated in macOS 10.12 @@ -734,29 +759,28 @@ SalFrame* AquaSalInstance::CreateChildFrame( SystemParentData*, SalFrameStyleFla SalFrame* AquaSalInstance::CreateFrame( SalFrame* pParent, SalFrameStyleFlags nSalFrameStyle ) { - SalData::ensureThreadAutoreleasePool(); - - SalFrame* pFrame = new AquaSalFrame( pParent, nSalFrameStyle ); - return pFrame; + OSX_INST_RUNINMAIN_POINTER( CreateFrame( pParent, nSalFrameStyle ), SalFrame* ) + return new AquaSalFrame( pParent, nSalFrameStyle ); } void AquaSalInstance::DestroyFrame( SalFrame* pFrame ) { + OSX_INST_RUNINMAIN( DestroyFrame( pFrame ) ) delete pFrame; } SalObject* AquaSalInstance::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, bool /* bShow */ ) { - AquaSalObject *pObject = nullptr; - - if ( pParent ) - pObject = new AquaSalObject( static_cast<AquaSalFrame*>(pParent), pWindowData ); + if ( !pParent ) + return nullptr; - return pObject; + OSX_INST_RUNINMAIN_POINTER( CreateObject( pParent, pWindowData, false ), SalObject* ) + return new AquaSalObject( static_cast<AquaSalFrame*>(pParent), pWindowData ); } void AquaSalInstance::DestroyObject( SalObject* pObject ) { + OSX_INST_RUNINMAIN( DestroyObject( pObject ) ) delete pObject; } diff --git a/vcl/osx/salobj.cxx b/vcl/osx/salobj.cxx index 957f017363fc..4113d43caf3c 100644 --- a/vcl/osx/salobj.cxx +++ b/vcl/osx/salobj.cxx @@ -26,6 +26,7 @@ #include "osx/salframe.h" #include "osx/salinst.h" #include "osx/salobj.h" +#include "osx/runinmain.hxx" #include <AppKit/NSOpenGLView.h> @@ -105,6 +106,8 @@ AquaSalObject::AquaSalObject( AquaSalFrame* pFrame, SystemWindowData* pWindowDat AquaSalObject::~AquaSalObject() { + assert( GetSalData()->mpFirstInstance->IsMainThread() ); + if( maSysData.mpNSView ) { NSView *pView = maSysData.mpNSView; @@ -194,6 +197,8 @@ void AquaSalObject::SetPosSize( long nX, long nY, long nWidth, long nHeight ) void AquaSalObject::setClippedPosSize() { + OSX_SALDATA_RUNINMAIN( setClippedPosSize() ) + NSRect aViewRect = { NSZeroPoint, NSMakeSize( mnWidth, mnHeight) }; if( maSysData.mpNSView ) { @@ -222,8 +227,12 @@ void AquaSalObject::setClippedPosSize() void AquaSalObject::Show( bool bVisible ) { - if( mpClipView ) - [mpClipView setHidden: (bVisible ? NO : YES)]; + if( !mpClipView ) + return; + + OSX_SALDATA_RUNINMAIN( Show( bVisible ) ) + + [mpClipView setHidden: (bVisible ? NO : YES)]; } const SystemEnvData* AquaSalObject::GetSystemData() const @@ -235,8 +244,10 @@ class AquaOpenGLContext : public OpenGLContext { public: virtual bool initWindow() override; + private: GLWindow m_aGLWin; + virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; } virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; } NSOpenGLView* getOpenGLView(); @@ -250,6 +261,8 @@ private: void AquaOpenGLContext::resetCurrent() { + OSX_SALDATA_RUNINMAIN( resetCurrent() ) + clearCurrent(); OpenGLZone aZone; @@ -260,6 +273,8 @@ void AquaOpenGLContext::resetCurrent() void AquaOpenGLContext::makeCurrent() { + OSX_SALDATA_RUNINMAIN( makeCurrent() ) + if (isCurrent()) return; @@ -275,6 +290,8 @@ void AquaOpenGLContext::makeCurrent() void AquaOpenGLContext::swapBuffers() { + OSX_SALDATA_RUNINMAIN( swapBuffers() ) + OpenGLZone aZone; NSOpenGLView* pView = getOpenGLView(); @@ -293,11 +310,14 @@ SystemWindowData AquaOpenGLContext::generateWinData(vcl::Window* /*pParent*/, bo void AquaOpenGLContext::destroyCurrentContext() { + OSX_SALDATA_RUNINMAIN( destroyCurrentContext() ) [NSOpenGLContext clearCurrentContext]; } bool AquaOpenGLContext::initWindow() { + OSX_SALDATA_RUNINMAIN_UNION( initWindow(), boolean ) + if( !m_pChildWindow ) { SystemWindowData winData = generateWinData(mpWindow, mbRequestLegacyContext); @@ -314,6 +334,8 @@ bool AquaOpenGLContext::initWindow() bool AquaOpenGLContext::ImplInit() { + OSX_SALDATA_RUNINMAIN_UNION( ImplInit(), boolean ) + OpenGLZone aZone; VCL_GL_INFO("OpenGLContext::ImplInit----start"); @@ -332,6 +354,7 @@ NSOpenGLView* AquaOpenGLContext::getOpenGLView() OpenGLContext* AquaSalInstance::CreateOpenGLContext() { + OSX_SALDATA_RUNINMAIN_POINTER( CreateOpenGLContext(), OpenGLContext* ) return new AquaOpenGLContext; } diff --git a/vcl/osx/saltimer.cxx b/vcl/osx/saltimer.cxx index 3cf74529a301..62814759ae1a 100644 --- a/vcl/osx/saltimer.cxx +++ b/vcl/osx/saltimer.cxx @@ -131,9 +131,10 @@ static void ImplSalStopTimer() void AquaSalTimer::handleDispatchTimerEvent() { ImplSVData* pSVData = ImplGetSVData(); - SolarMutexGuard aGuard; + GetSalData()->mpFirstInstance->AcquireYieldMutex( 1 ); if( pSVData->maSchedCtx.mpSalTimer ) pSVData->maSchedCtx.mpSalTimer->CallCallback(); + GetSalData()->mpFirstInstance->ReleaseYieldMutex( false ); } void AquaSalTimer::handleStartTimerEvent( NSEvent* pEvent ) diff --git a/vcl/source/window/winproc.cxx b/vcl/source/window/winproc.cxx index bc9c4682d258..de4ec66e88e2 100644 --- a/vcl/source/window/winproc.cxx +++ b/vcl/source/window/winproc.cxx @@ -2267,7 +2267,9 @@ static void ImplHandleSalQueryCharPosition( vcl::Window *pWindow, bool ImplWindowFrameProc( vcl::Window* _pWindow, SalEvent nEvent, const void* pEvent ) { +#ifndef MACOSX DBG_TESTSOLARMUTEX(); +#endif // Ensure the window survives during this method. VclPtr<vcl::Window> pWindow( _pWindow ); commit 53c12f0925ec5538612c1239650a885bad3c5c00 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Wed Aug 9 17:38:46 2017 +0200 OSX dispatch user events via main loop Otherwise we deadlock when dispatching ChangeRequestQueueProcessor events from Java unit tests / UNO. Change-Id: I2e9142650f5de83f0f4f382d90866e6d89f4eec8 diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h index 5b74594a1c97..f47ae7cc8303 100644 --- a/vcl/inc/osx/salinst.h +++ b/vcl/inc/osx/salinst.h @@ -69,7 +69,6 @@ public: SalYieldMutex* mpSalYieldMutex; // Sal-Yield-Mutex OUString maDefaultPrinter; oslThreadIdentifier maMainThread; - bool mbWaitingYield; int mnActivePrintJobs; std::list< SalUserEvent > maUserEvents; osl::Mutex maUserEventListMutex; @@ -128,14 +127,12 @@ public: virtual css::uno::Reference< css::uno::XInterface > CreateDragSource() override; virtual css::uno::Reference< css::uno::XInterface > CreateDropTarget() override; - static void handleAppDefinedEvent( NSEvent* pEvent ); + void handleAppDefinedEvent( NSEvent* pEvent ); // check whether a particular string is passed on the command line // this is needed to avoid duplicate open events through a) command line and b) NSApp's openFile static bool isOnCommandLine( const OUString& ); - void wakeupYield(); - public: friend class AquaSalFrame; @@ -152,7 +149,7 @@ public: static const short AppExecuteSVMain = 0x7fff; static const short AppEndLoopEvent = 1; static const short AppStartTimerEvent = 10; - static const short YieldWakeupEvent = 20; + static const short PostedUserEvent = 20; static const short DispatchTimerEvent = 30; static NSMenu* GetDynamicDockMenu(); diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index 6e091cb116ce..45b7da6e36ee 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -353,7 +353,6 @@ AquaSalInstance::AquaSalInstance() mpSalYieldMutex->acquire(); ::comphelper::SolarMutex::setSolarMutex( mpSalYieldMutex ); maMainThread = osl::Thread::getCurrentIdentifier(); - mbWaitingYield = false; mnActivePrintJobs = 0; } @@ -364,13 +363,6 @@ AquaSalInstance::~AquaSalInstance() delete mpSalYieldMutex; } -void AquaSalInstance::wakeupYield() -{ - // wakeup :Yield - if( mbWaitingYield ) - ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, YES ); -} - void AquaSalInstance::PostUserEvent( AquaSalFrame* pFrame, SalEvent nType, void* pData ) { { @@ -378,7 +370,9 @@ void AquaSalInstance::PostUserEvent( AquaSalFrame* pFrame, SalEvent nType, void* maUserEvents.push_back( SalUserEvent( pFrame, pData, nType ) ); } // notify main loop that an event has arrived - wakeupYield(); + dispatch_async(dispatch_get_main_queue(),^{ + ImplNSAppPostEvent( AquaSalInstance::PostedUserEvent, NO ); + }); } comphelper::SolarMutex* AquaSalInstance::GetYieldMutex() @@ -463,6 +457,28 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent ) case DispatchTimerEvent: AquaSalTimer::handleDispatchTimerEvent(); break; + case PostedUserEvent: + { + // get one user event + SalUserEvent aEvent( nullptr, nullptr, SalEvent::NONE ); + { + osl::MutexGuard g( maUserEventListMutex ); + if ( !maUserEvents.empty() ) + { + aEvent = maUserEvents.front(); + maUserEvents.pop_front(); + } + } + + // dispatch it + if ( aEvent.mpFrame ) + { + osl::Guard< comphelper::SolarMutex > aGuard( *mpSalYieldMutex ); + if ( AquaSalFrame::isAlive( aEvent.mpFrame ) ) + aEvent.mpFrame->CallCallback( aEvent.mnType, aEvent.mpData ); + } + break; + } #if !HAVE_FEATURE_MACOSX_SANDBOX case AppleRemoteControlEvent: // Defined in <apple_remote/RemoteMainController.h> { @@ -529,10 +545,6 @@ void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent ) break; #endif - case YieldWakeupEvent: - // do nothing, fall out of Yield - break; - default: OSL_FAIL( "unhandled NSApplicationDefined event" ); break; @@ -553,46 +565,10 @@ bool AquaSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents, sal_uLon // an own pool for each yield level ReleasePoolHolder aReleasePool; - // Release all locks so that we don't deadlock when we pull pending - // events from the event queue - bool bDispatchUser = true; - while( bDispatchUser ) - { - // get one user event - SalUserEvent aEvent( nullptr, nullptr, SalEvent::NONE ); - { - osl::MutexGuard g( maUserEventListMutex ); - if( ! maUserEvents.empty() ) - { - aEvent = maUserEvents.front(); - maUserEvents.pop_front(); - bHadEvent = true; - } - else - bDispatchUser = false; - } - - // dispatch it - if( aEvent.mpFrame && AquaSalFrame::isAlive( aEvent.mpFrame ) ) - { - aEvent.mpFrame->CallCallback( aEvent.mnType, aEvent.mpData ); - maWaitingYieldCond.set(); - } - - // return if only one event is asked for - if( !bHandleAllCurrentEvents && bDispatchUser ) - return true; - } - // handle cocoa event queue // cocoa events may be only handled in the thread the NSApp was created if( IsMainThread() && mnActivePrintJobs == 0 ) { - // we need to be woken up by a cocoa-event - // if a user event should be posted by the event handling below - bool bOldWaitingYield = mbWaitingYield; - mbWaitingYield = bWait; - // handle available events NSEvent* pEvent = nil; do @@ -636,8 +612,6 @@ SAL_WNODEPRECATED_DECLARATIONS_POP AcquireYieldMutex( nCount ); } - mbWaitingYield = bOldWaitingYield; - // collect update rectangles const std::list< AquaSalFrame* > rFrames( GetSalData()->maFrames ); for( std::list< AquaSalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) diff --git a/vcl/osx/vclnsapp.mm b/vcl/osx/vclnsapp.mm index 2add55ffde85..a98d12aeb1ab 100644 --- a/vcl/osx/vclnsapp.mm +++ b/vcl/osx/vclnsapp.mm @@ -91,7 +91,7 @@ SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12 if( eType == NSApplicationDefined ) { - AquaSalInstance::handleAppDefinedEvent( pEvent ); + GetSalData()->mpFirstInstance->handleAppDefinedEvent( pEvent ); } else if( eType == NSKeyDown && ([pEvent modifierFlags] & NSCommandKeyMask) != 0 ) { commit 5b1deb7ae05e198cdf59075afafbfce67915ec3f Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 15 08:20:18 2017 +0200 Add (DY)LD_LIBRARY_PATH to environment output Change-Id: I53604afa0c7f31f4eb7eed29793a49f7a1e037aa diff --git a/odk/config/setsdkenv_unix.sh.in b/odk/config/setsdkenv_unix.sh.in index 61f5c5a07651..fd27607db5d0 100644 --- a/odk/config/setsdkenv_unix.sh.in +++ b/odk/config/setsdkenv_unix.sh.in @@ -296,5 +296,6 @@ echo " * C++ Compiler = $OO_SDK_CPP_HOME" echo " * Java = $OO_SDK_JAVA_HOME" echo " * SDK Output directory = $OO_SDK_OUT" echo " * Auto deployment = $SDK_AUTO_DEPLOYMENT" +echo " * Library path = ${DYLD_LIBRARY_PATH}${LD_LIBRARY_PATH}" echo " *" echo " ************************************************************************" commit 4511edbbf583dfa84dfa1bd11c3177edc65524aa Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 15 08:05:51 2017 +0200 Optionally release one or all yield locks Adds an additional boolean parameter to ReleaseYieldMutex. In theory nobody should depend on the plain mutex. Change-Id: If7fa108067e6c6b91d14f04df22984021649711f diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h index 8468dbd8dd59..5b74594a1c97 100644 --- a/vcl/inc/osx/salinst.h +++ b/vcl/inc/osx/salinst.h @@ -104,7 +104,7 @@ public: virtual SalSystem* CreateSalSystem() override; virtual SalBitmap* CreateSalBitmap() override; virtual comphelper::SolarMutex* GetYieldMutex() override; - virtual sal_uLong ReleaseYieldMutex() override; + virtual sal_uLong ReleaseYieldMutex( bool bUnlockAll = true ) override; virtual void AcquireYieldMutex( sal_uLong nCount ) override; virtual bool CheckYieldMutex() override; virtual bool DoYield(bool bWait, bool bHandleAllCurrentEvents, diff --git a/vcl/inc/salinst.hxx b/vcl/inc/salinst.hxx index 03491553c62a..fc8febbf035f 100644 --- a/vcl/inc/salinst.hxx +++ b/vcl/inc/salinst.hxx @@ -121,7 +121,7 @@ public: // YieldMutex virtual comphelper::SolarMutex* GetYieldMutex() = 0; - virtual sal_uLong ReleaseYieldMutex() = 0; + virtual sal_uLong ReleaseYieldMutex( bool bUnlockAll = true ) = 0; virtual void AcquireYieldMutex( sal_uLong nCount ) = 0; // return true, if yield mutex is owned by this thread, else false virtual bool CheckYieldMutex() = 0; diff --git a/vcl/inc/unx/geninst.h b/vcl/inc/unx/geninst.h index 2c99a7b3e0a1..ef747fa323af 100644 --- a/vcl/inc/unx/geninst.h +++ b/vcl/inc/unx/geninst.h @@ -84,7 +84,7 @@ public: // Yield mutex virtual comphelper::SolarMutex* GetYieldMutex() override; - virtual sal_uIntPtr ReleaseYieldMutex() override; + virtual sal_uIntPtr ReleaseYieldMutex( bool bUnlockAll = true ) override; virtual void AcquireYieldMutex( sal_uIntPtr nCount ) override; virtual bool CheckYieldMutex() override; diff --git a/vcl/inc/win/salinst.h b/vcl/inc/win/salinst.h index 03ba573c523b..3683e9369cfa 100644 --- a/vcl/inc/win/salinst.h +++ b/vcl/inc/win/salinst.h @@ -59,7 +59,7 @@ public: virtual SalSystem* CreateSalSystem() override; virtual SalBitmap* CreateSalBitmap() override; virtual comphelper::SolarMutex* GetYieldMutex() override; - virtual sal_uIntPtr ReleaseYieldMutex() override; + virtual sal_uIntPtr ReleaseYieldMutex( bool bUnlockAll = true ) override; virtual void AcquireYieldMutex( sal_uIntPtr nCount ) override; virtual bool CheckYieldMutex() override; virtual bool IsMainThread() const override; diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index f22e88f02793..6e091cb116ce 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -386,13 +386,14 @@ comphelper::SolarMutex* AquaSalInstance::GetYieldMutex() return mpSalYieldMutex; } -sal_uLong AquaSalInstance::ReleaseYieldMutex() +sal_uLong AquaSalInstance::ReleaseYieldMutex( bool bUnlockAll ) { SalYieldMutex* pYieldMutex = mpSalYieldMutex; if ( pYieldMutex->GetThreadId() == osl::Thread::getCurrentIdentifier() ) { - sal_uLong nCount = pYieldMutex->GetAcquireCount(); + const sal_uLong nCurCount = pYieldMutex->GetAcquireCount(); + const sal_uLong nCount = bUnlockAll ? nCurCount : 1; sal_uLong n = nCount; while ( n ) { diff --git a/vcl/unx/generic/app/geninst.cxx b/vcl/unx/generic/app/geninst.cxx index 29b4c754da84..b5a954f591f3 100644 --- a/vcl/unx/generic/app/geninst.cxx +++ b/vcl/unx/generic/app/geninst.cxx @@ -88,7 +88,7 @@ comphelper::SolarMutex* SalGenericInstance::GetYieldMutex() return mpSalYieldMutex.get(); } -sal_uLong SalGenericInstance::ReleaseYieldMutex() +sal_uLong SalGenericInstance::ReleaseYieldMutex( bool ) { SalYieldMutex* pYieldMutex = mpSalYieldMutex.get(); if ( pYieldMutex->GetThreadId() == diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx index 7ea3bd526675..1082b278a041 100644 --- a/vcl/win/app/salinst.cxx +++ b/vcl/win/app/salinst.cxx @@ -538,7 +538,7 @@ comphelper::SolarMutex* WinSalInstance::GetYieldMutex() return mpSalYieldMutex; } -sal_uLong WinSalInstance::ReleaseYieldMutex() +sal_uLong WinSalInstance::ReleaseYieldMutex( bool ) { return ImplSalReleaseYieldMutex(); } commit 0b695b982eadaf0c6fb5e1888a27ff88394b0a06 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 15 07:52:12 2017 +0200 Really run the layouter every 50ms By Start()-ing the Idle, it's always reset, so with fast resizes you could actually postpone layouting indefinitly. Change-Id: Ie90b6f3f378ee8d163f621fce51280e09c826f14 diff --git a/framework/source/layoutmanager/layoutmanager.cxx b/framework/source/layoutmanager/layoutmanager.cxx index 373b2c73e159..a8dca9cc3fce 100644 --- a/framework/source/layoutmanager/layoutmanager.cxx +++ b/framework/source/layoutmanager/layoutmanager.cxx @@ -2199,9 +2199,9 @@ void SAL_CALL LayoutManager::unlock() // conform to documentation: unlock with lock count == 0 means force a layout SolarMutexClearableGuard aWriteLock; - if ( bDoLayout ) - m_aAsyncLayoutTimer.Stop(); - aWriteLock.clear(); + if ( bDoLayout ) + m_aAsyncLayoutTimer.Stop(); + aWriteLock.clear(); Any a( nLockCount ); implts_notifyListeners( frame::LayoutManagerEvents::UNLOCK, a ); @@ -2598,9 +2598,9 @@ void SAL_CALL LayoutManager::windowResized( const awt::WindowEvent& aEvent ) if ( !m_aAsyncLayoutTimer.IsActive() ) { m_aAsyncLayoutTimer.Invoke(); + if ( m_nLockCount == 0 ) + m_aAsyncLayoutTimer.Start(); } - if ( m_nLockCount == 0 ) - m_aAsyncLayoutTimer.Start(); } else if ( m_xFrame.is() && aEvent.Source == m_xFrame->getContainerWindow() ) { @@ -2670,7 +2670,6 @@ void SAL_CALL LayoutManager::windowHidden( const lang::EventObject& aEvent ) IMPL_LINK_NOARG(LayoutManager, AsyncLayoutHdl, Timer *, void) { SolarMutexClearableGuard aReadLock; - m_aAsyncLayoutTimer.Stop(); if( !m_xContainerWindow.is() ) return; commit 914ecc008d2ab3e4490bea385324e0005df121d9 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Wed Aug 9 17:48:48 2017 +0200 Remove 500ns offset from GetSystemTicks() This doesn't make any sense. The orignal idea might have been to somehow be in the middle of 1ms, for whatever reason. And it completely breaks, if we want to sleep 0ms. Change-Id: I525b70c016876a96aa17edefe8c076b122ee2527 diff --git a/tools/source/datetime/ttime.cxx b/tools/source/datetime/ttime.cxx index 2c0ebe4a1b53..83812f72171a 100644 --- a/tools/source/datetime/ttime.cxx +++ b/tools/source/datetime/ttime.cxx @@ -433,7 +433,7 @@ sal_uInt64 tools::Time::GetSystemTicks() SAL_WARN("tools.datetime", "gettimeofday failed: " << e); } return static_cast<sal_uInt64>(tv.tv_sec) * 1000 - + (static_cast<sal_uInt64>(tv.tv_usec) + 500) / 1000; + + static_cast<sal_uInt64>(tv.tv_usec) / 1000; #endif } commit 52a9b2f07de5bac661ef2583ff5c70842b796eb5 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 8 15:02:52 2017 +0200 The scheduler timer runs without SolarMutex The backend is resposible to correctly start the timer. Otherwise you can't start new Tasks without the SolarMutex. Change-Id: I4e066fceb513d0de90b58854baf3e45f2b8ff25b diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx index e9b75dcfc674..50a45006ced1 100644 --- a/vcl/source/app/scheduler.cxx +++ b/vcl/source/app/scheduler.cxx @@ -201,8 +201,6 @@ void Scheduler::ImplStartTimer(sal_uInt64 nMS, bool bForce, sal_uInt64 nTime) if ( !rSchedCtx.mbActive ) return; - DBG_TESTSOLARMUTEX(); - if (!rSchedCtx.mpSalTimer) { rSchedCtx.mnTimerStart = 0; commit 4be61f8ad83cc17f4ac516396092e861ae4176ff Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Mon Aug 7 21:10:11 2017 +0200 Don't poll the extension install progress bar Just start the Idle, if actually something changed. Quite probably we shouldn't rely on an Idle at all, but this fixes the busy loop while installing an extension waiting in a confirmation dialog. Change-Id: I3abbe2eb6651ce9320ef6e4d9c5251a23ab87216 diff --git a/desktop/source/deployment/gui/dp_gui_dialog2.cxx b/desktop/source/deployment/gui/dp_gui_dialog2.cxx index 80a46523557b..8b311528e7ce 100644 --- a/desktop/source/deployment/gui/dp_gui_dialog2.cxx +++ b/desktop/source/deployment/gui/dp_gui_dialog2.cxx @@ -519,6 +519,7 @@ ExtMgrDialog::ExtMgrDialog(vcl::Window *pParent, TheExtensionManager *pManager, } m_aIdle.SetPriority(TaskPriority::LOWEST); + m_aIdle.SetDebugName( "ExtMgrDialog m_aIdle TimeOutHdl" ); m_aIdle.SetInvokeHandler( LINK( this, ExtMgrDialog, TimeOutHdl ) ); } @@ -855,14 +856,18 @@ void ExtMgrDialog::showProgress( bool _bStart ) } DialogHelper::PostUserEvent( LINK( this, ExtMgrDialog, startProgress ), reinterpret_cast<void*>(bStart) ); + m_aIdle.Start(); } void ExtMgrDialog::updateProgress( const long nProgress ) { - ::osl::MutexGuard aGuard( m_aMutex ); - - m_nProgress = nProgress; + if ( m_nProgress != nProgress ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_nProgress = nProgress; + m_aIdle.Start(); + } } @@ -874,6 +879,7 @@ void ExtMgrDialog::updateProgress( const OUString &rText, m_xAbortChannel = xAbortChannel; m_sProgressText = rText; m_bProgressChanged = true; + m_aIdle.Start(); } @@ -991,8 +997,6 @@ IMPL_LINK_NOARG(ExtMgrDialog, TimeOutHdl, Timer *, void) if ( m_pProgressBar->IsVisible() ) m_pProgressBar->SetValue( (sal_uInt16) m_nProgress ); - - m_aIdle.Start(); } } @@ -1079,6 +1083,7 @@ UpdateRequiredDialog::UpdateRequiredDialog(vcl::Window *pParent, TheExtensionMan m_pCloseBtn->GrabFocus(); m_aIdle.SetPriority( TaskPriority::LOWEST ); + m_aIdle.SetDebugName( "UpdateRequiredDialog m_aIdle TimeOutHdl" ); m_aIdle.SetInvokeHandler( LINK( this, UpdateRequiredDialog, TimeOutHdl ) ); } @@ -1195,14 +1200,18 @@ void UpdateRequiredDialog::showProgress( bool _bStart ) } DialogHelper::PostUserEvent( LINK( this, UpdateRequiredDialog, startProgress ), reinterpret_cast<void*>(bStart) ); + m_aIdle.Start(); } void UpdateRequiredDialog::updateProgress( const long nProgress ) { - ::osl::MutexGuard aGuard( m_aMutex ); - - m_nProgress = nProgress; + if ( m_nProgress != nProgress ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_nProgress = nProgress; + m_aIdle.Start(); + } } @@ -1214,6 +1223,7 @@ void UpdateRequiredDialog::updateProgress( const OUString &rText, m_xAbortChannel = xAbortChannel; m_sProgressText = rText; m_bProgressChanged = true; + m_aIdle.Start(); } @@ -1301,8 +1311,6 @@ IMPL_LINK_NOARG(UpdateRequiredDialog, TimeOutHdl, Timer *, void) if ( m_pProgressBar->IsVisible() ) m_pProgressBar->SetValue( (sal_uInt16) m_nProgress ); - - m_aIdle.Start(); } } diff --git a/desktop/source/deployment/gui/dp_gui_dialog2.hxx b/desktop/source/deployment/gui/dp_gui_dialog2.hxx index 60a87d75b6e5..cf4f423b83f7 100644 --- a/desktop/source/deployment/gui/dp_gui_dialog2.hxx +++ b/desktop/source/deployment/gui/dp_gui_dialog2.hxx @@ -141,7 +141,7 @@ class ExtMgrDialog : public ModelessDialog, DECL_LINK( HandleCancelBtn, Button*, void ); DECL_LINK( HandleCloseBtn, Button*, void ); DECL_LINK( HandleExtTypeCbx, Button*, void ); - DECL_LINK(TimeOutHdl, Timer *, void); + DECL_LINK( TimeOutHdl, Timer *, void ); DECL_LINK( startProgress, void *, void ); DECL_STATIC_LINK( ExtMgrDialog, Restart, void *, void ); @@ -214,7 +214,7 @@ class UpdateRequiredDialog : public ModalDialog, DECL_LINK( HandleUpdateBtn, Button*, void ); DECL_LINK( HandleCloseBtn, Button*, void ); DECL_LINK( HandleCancelBtn, Button*, void ); - DECL_LINK(TimeOutHdl, Timer *, void); + DECL_LINK( TimeOutHdl, Timer *, void ); DECL_LINK( startProgress, void *, void ); static bool isEnabled( const css::uno::Reference< css::deployment::XPackage > &xPackage ); diff --git a/vcl/osx/salnativewidgets.cxx b/vcl/osx/salnativewidgets.cxx index 56ac7f2131bf..39cb514ddcbf 100644 --- a/vcl/osx/salnativewidgets.cxx +++ b/vcl/osx/salnativewidgets.cxx @@ -50,18 +50,18 @@ class AquaBlinker : public Timer tools::Rectangle maInvalidateRect; AquaBlinker( AquaSalFrame* pFrame, const tools::Rectangle& rRect ) - : mpFrame( pFrame ), maInvalidateRect( rRect ) + : Timer( "AquaBlinker" ) + , mpFrame( pFrame ) + , maInvalidateRect( rRect ) { mpFrame->maBlinkers.push_back( this ); } - public: - +public: static void Blink( AquaSalFrame*, const tools::Rectangle&, int nTimeout = 80 ); virtual void Invoke() override { - Stop(); if( AquaSalFrame::isAlive( mpFrame ) && mpFrame->mbShown ) { mpFrame->maBlinkers.remove( this ); commit 9afd654af7f4847ecba81b3315f9ead27a1f37eb Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Fri Jul 28 17:13:20 2017 +0200 WIP Assert active Tasks on scheduler DeInit This shuts down the VCL scheduler later in the DeInitVCL call and asserts active pending tasks, as these will never be processed after shutdown. There is currently a TODO whitelist, so the unit tests still pass but probably most of these should be fixed. No task in the list looks critical - all seem to do some idle / cleanup work. This also processes all the Idles before shutdown. All seem to be of type sfx::SfxItemDisruptor_Impl. Change-Id: I9cc484a525cc2bacd54c4f271f86997517393e92 diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx index 54e04dad76ca..f22e88f02793 100644 --- a/vcl/osx/salinst.cxx +++ b/vcl/osx/salinst.cxx @@ -108,6 +108,7 @@ void AquaSalInstance::delayedSettingsChanged( bool bInvalidate ) { osl::Guard< comphelper::SolarMutex > aGuard( *mpSalYieldMutex ); AquaDelayedSettingsChanged* pIdle = new AquaDelayedSettingsChanged( bInvalidate ); + pIdle->SetDebugName( "AquaSalInstance AquaDelayedSettingsChanged" ); pIdle->Start(); } diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx index 72653436e1c6..e9b75dcfc674 100644 --- a/vcl/source/app/scheduler.cxx +++ b/vcl/source/app/scheduler.cxx @@ -95,6 +95,8 @@ void Scheduler::ImplDeInitScheduler() DBG_TESTSOLARMUTEX(); SchedulerGuard aSchedulerGuard; + // clean up all the sfx::SfxItemDisruptor_Impl Idles + ProcessEventsToIdle(); rSchedCtx.mbActive = false; assert( nullptr == rSchedCtx.mpSchedulerStack ); @@ -104,18 +106,47 @@ void Scheduler::ImplDeInitScheduler() DELETEZ( rSchedCtx.mpSalTimer ); ImplSchedulerData* pSchedulerData = rSchedCtx.mpFirstSchedulerData; + sal_uInt32 nActiveTasks = 0, nIgnoredTasks = 0; while ( pSchedulerData ) { Task *pTask = pSchedulerData->mpTask; if ( pTask ) { - pTask->mbActive = false; + if ( pTask->mbActive ) + { + const char *sIgnored = ""; + ++nActiveTasks; + // TODO: shutdown these timers before Scheduler DeInit + if ( pTask->GetDebugName() && ( + !strcmp( pTask->GetDebugName(), "svx OLEObjCache pTimer UnloadCheck" ) + || !strcmp( pTask->GetDebugName(), "svtools::GraphicCache maReleaseTimer" ) + || !strcmp( pTask->GetDebugName(), "editeng::ImpEditEngine aOnlineSpellTimer" ) + || !strcmp( pTask->GetDebugName(), "sc::ScModule aIdleTimer" ) + || !strcmp( pTask->GetDebugName(), "sd::CacheConfiguration maReleaseTimer" ) + || !strcmp( pTask->GetDebugName(), "svtools::GraphicObject mpSwapOutTimer" ) + || !strcmp( pTask->GetDebugName(), "desktop::Desktop m_firstRunTimer" ) + || !strcmp( pTask->GetDebugName(), "vcl::win GdiPlusBuffer aGdiPlusBuffer" ) + )) + { + sIgnored = " (ignored)"; + ++nIgnoredTasks; + } + const Timer *timer = dynamic_cast<Timer*>( pTask ); + if ( timer ) + SAL_WARN( "vcl.schedule", "DeInit task: " << *timer << sIgnored ); + else + SAL_WARN( "vcl.schedule", "DeInit task: " << *pTask << sIgnored ); + pTask->mbActive = false; + } pTask->mpSchedulerData = nullptr; } ImplSchedulerData* pDeleteSchedulerData = pSchedulerData; pSchedulerData = pSchedulerData->mpNext; delete pDeleteSchedulerData; } + SAL_WARN_IF( 0 != nActiveTasks, "vcl.schedule", "DeInit active tasks: " + << nActiveTasks << " (ignored: " << nIgnoredTasks << ")" ); + assert( nIgnoredTasks == nActiveTasks ); rSchedCtx.mpFirstSchedulerData = nullptr; rSchedCtx.mpLastSchedulerData = nullptr; diff --git a/vcl/source/app/svmain.cxx b/vcl/source/app/svmain.cxx index 1b88fc290157..4853fe74acea 100644 --- a/vcl/source/app/svmain.cxx +++ b/vcl/source/app/svmain.cxx @@ -462,8 +462,6 @@ void DeInitVCL() pSVData->mpSettingsConfigItem = nullptr; } - Scheduler::ImplDeInitScheduler(); - pSVData->maWinData.maMsgBoxImgList.clear(); pSVData->maCtrlData.maCheckImgList.clear(); pSVData->maCtrlData.maRadioImgList.clear(); @@ -571,6 +569,8 @@ void DeInitVCL() delete pSVData->maGDIData.mpScreenFontCache; pSVData->maGDIData.mpScreenFontCache = nullptr; + Scheduler::ImplDeInitScheduler(); + // destroy all Sal interfaces before destroying the instance // and thereby unloading the plugin delete pSVData->mpSalSystem; @@ -604,6 +604,7 @@ void DeInitVCL() pSVData->maWinData.mpTrackWin = nullptr; pSVData->maWinData.mpAutoScrollWin = nullptr; pSVData->maWinData.mpLastWheelWindow = nullptr; + // Deinit Sal if (pSVData->mpDefInst) { commit 0f28c083d22ea6026485fdf08a831dcd862e9c57 Author: Jan-Marek Glogowski <glo...@fbihome.de> Date: Tue Aug 15 08:42:56 2017 +0200 Get system thread ID from LOs own identifier Stores the system TID for Linux and MacOS. On Windows the internal TID is already the system TID. Converts Thread_Impl into a real class and also replaces the own hashmap with a std::unordered_map. Change-Id: I18f822c3ceb82c7655405cda4b8e2c2ef0211207 diff --git a/include/osl/thread.h b/include/osl/thread.h index be7999e5468d..a9adb484ed0a 100644 --- a/include/osl/thread.h +++ b/include/osl/thread.h @@ -58,6 +58,7 @@ typedef enum typedef sal_uInt32 oslThreadIdentifier; +typedef sal_uInt64 oslThreadSystemTID; typedef void* oslThreadKey; @@ -85,6 +86,13 @@ SAL_DLLPUBLIC oslThread SAL_CALL osl_createSuspendedThread(oslWorkerFunction pWo */ SAL_DLLPUBLIC oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread); +/** Get the system specific identifier for the specified thread + or if parameter Thread is NULL of the current active thread. + If the result is 0, no system specific TID is available. + @return system identifier of the thread +*/ +SAL_DLLPUBLIC oslThreadSystemTID SAL_CALL osl_getSystemTID(oslThread Thread); + /** Release the thread handle. If Thread is NULL, the function won't do anything. Note that we do not interfere with the actual running of diff --git a/sal/osl/unx/thread.cxx b/sal/osl/unx/thread.cxx index 3e6b36a2c8ca..c37d1b703736 100644 --- a/sal/osl/unx/thread.cxx +++ b/sal/osl/unx/thread.cxx @@ -22,6 +22,7 @@ #include <cassert> #include <cstddef> #include <functional> +#include <unordered_map> #include "system.hxx" #include <string.h> @@ -30,6 +31,7 @@ #endif ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits