Avoid potential negative array index access to cached text.
[LibreOffice.git] / vcl / inc / osx / runinmain.hxx
blobe68bc4d350104c0964856cc007e9fbb32ed5fe61
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #ifndef INCLUDED_VCL_INC_OSX_RUNINMAIN_HXX
21 #define INCLUDED_VCL_INC_OSX_RUNINMAIN_HXX
23 /**
24 * Runs a command in the main thread.
26 * These macros are always used like a recursive calls, so they work like
27 * a closure.
29 * Uses two conditionals for a two way communication.
30 * The data (code block + result) is protected by the SolarMutex.
32 * There are three main macros, which act as function initializers:
33 * - OSX_RUNINMAIN - for all functions without return values
34 * - OSX_RUNINMAIN_POINTER - for all functions returning a pointer
35 * - OSX_RUNINMAIN_UNION - for all other return types
37 * All types used via OSX_RUNINMAIN_UNION must implement a move constructor,
38 * so there is no memory leak!
41 #include <unordered_map>
43 #include <Block.h>
45 #include <osl/thread.h>
47 #include "saltimer.h"
48 #include <salframe.hxx>
49 #include <tools/debug.hxx>
51 union RuninmainResult
53 void* pointer;
54 bool boolean;
55 struct SalFrame::SalPointerState state;
57 RuninmainResult() {}
60 #define OSX_RUNINMAIN_MEMBERS \
61 std::mutex m_runInMainMutex; \
62 std::condition_variable m_aInMainCondition; \
63 std::condition_variable m_aResultCondition; \
64 bool m_wakeUpMain = false; \
65 bool m_resultReady = false; \
66 RuninmainBlock m_aCodeBlock; \
67 RuninmainResult m_aResult;
69 #define OSX_RUNINMAIN( instance, command ) \
70 if ( !instance->IsMainThread() ) \
71 { \
72 DBG_TESTSOLARMUTEX(); \
73 SalYieldMutex *aMutex = static_cast<SalYieldMutex*>(instance->GetYieldMutex()); \
74 { \
75 std::scoped_lock<std::mutex> g(aMutex->m_runInMainMutex); \
76 assert( !aMutex->m_aCodeBlock ); \
77 aMutex->m_aCodeBlock = Block_copy(^{ \
78 command; \
79 }); \
80 aMutex->m_wakeUpMain = true; \
81 aMutex->m_aInMainCondition.notify_all(); \
82 } \
83 dispatch_async(dispatch_get_main_queue(),^{ \
84 ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, NO ); \
85 }); \
86 { \
87 std::unique_lock<std::mutex> g(aMutex->m_runInMainMutex); \
88 aMutex->m_aResultCondition.wait( \
89 g, [&aMutex]() { return aMutex->m_resultReady; }); \
90 aMutex->m_resultReady = false; \
91 } \
92 return; \
95 #define OSX_RUNINMAIN_POINTER( instance, command, type ) \
96 if ( !instance->IsMainThread() ) \
97 { \
98 DBG_TESTSOLARMUTEX(); \
99 SalYieldMutex *aMutex = static_cast<SalYieldMutex*>(instance->GetYieldMutex()); \
101 std::scoped_lock<std::mutex> g(aMutex->m_runInMainMutex); \
102 assert( !aMutex->m_aCodeBlock ); \
103 aMutex->m_aCodeBlock = Block_copy(^{ \
104 aMutex->m_aResult.pointer = static_cast<void*>( command ); \
105 }); \
106 aMutex->m_wakeUpMain = true; \
107 aMutex->m_aInMainCondition.notify_all(); \
109 dispatch_async(dispatch_get_main_queue(),^{ \
110 ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, NO ); \
111 }); \
113 std::unique_lock<std::mutex> g(aMutex->m_runInMainMutex); \
114 aMutex->m_aResultCondition.wait( \
115 g, [&aMutex]() { return aMutex->m_resultReady; }); \
116 aMutex->m_resultReady = false; \
118 return static_cast<type>( aMutex->m_aResult.pointer ); \
121 #define OSX_RUNINMAIN_UNION( instance, command, member ) \
122 if ( !instance->IsMainThread() ) \
124 DBG_TESTSOLARMUTEX(); \
125 SalYieldMutex *aMutex = static_cast<SalYieldMutex*>(instance->GetYieldMutex()); \
127 std::scoped_lock<std::mutex> g(aMutex->m_runInMainMutex); \
128 assert( !aMutex->m_aCodeBlock ); \
129 aMutex->m_aCodeBlock = Block_copy(^{ \
130 aMutex->m_aResult.member = command; \
131 }); \
132 aMutex->m_wakeUpMain = true; \
133 aMutex->m_aInMainCondition.notify_all(); \
135 dispatch_async(dispatch_get_main_queue(),^{ \
136 ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, NO ); \
137 }); \
139 std::unique_lock<std::mutex> g(aMutex->m_runInMainMutex); \
140 aMutex->m_aResultCondition.wait( \
141 g, [&aMutex]() { return aMutex->m_resultReady; }); \
142 aMutex->m_resultReady = false; \
144 return std::move( aMutex->m_aResult.member ); \
148 * convenience macros used from SalInstance
151 #define OSX_INST_RUNINMAIN( command ) \
152 OSX_RUNINMAIN( this, command )
154 #define OSX_INST_RUNINMAIN_POINTER( command, type ) \
155 OSX_RUNINMAIN_POINTER( this, command, type )
157 #define OSX_INST_RUNINMAIN_UNION( command, member ) \
158 OSX_RUNINMAIN_UNION( this, command, member )
161 * convenience macros using global SalData
164 #define OSX_SALDATA_RUNINMAIN( command ) \
165 OSX_RUNINMAIN( GetSalData()->mpInstance, command )
167 #define OSX_SALDATA_RUNINMAIN_POINTER( command, type ) \
168 OSX_RUNINMAIN_POINTER( GetSalData()->mpInstance, command, type )
170 #define OSX_SALDATA_RUNINMAIN_UNION( command, member ) \
171 OSX_RUNINMAIN_UNION( GetSalData()->mpInstance, command, member )
173 #endif // INCLUDED_VCL_INC_OSX_RUNINMAIN_HXX
175 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */