2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "ApplicationMessenger.h"
11 #include "guilib/GUIMessage.h"
12 #include "messaging/IMessageTarget.h"
13 #include "threads/SingleLock.h"
14 #include "utils/log.h"
15 #include "windowing/GraphicContext.h"
26 class CDelayedMessage
: public CThread
29 CDelayedMessage(const ThreadMessage
& msg
, unsigned int delay
);
30 void Process() override
;
37 CDelayedMessage::CDelayedMessage(const ThreadMessage
& msg
, unsigned int delay
)
38 : CThread("DelayedMessage"), m_msg(msg
)
43 void CDelayedMessage::Process()
45 CThread::Sleep(std::chrono::milliseconds(m_delay
));
48 CServiceBroker::GetAppMessenger()->PostMsg(m_msg
.dwMessage
, m_msg
.param1
, m_msg
.param1
,
49 m_msg
.lpVoid
, m_msg
.strParam
, m_msg
.params
);
52 CApplicationMessenger::CApplicationMessenger() = default;
54 CApplicationMessenger::~CApplicationMessenger()
59 void CApplicationMessenger::Cleanup()
61 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
63 while (!m_vecMessages
.empty())
65 ThreadMessage
* pMsg
= m_vecMessages
.front();
68 pMsg
->waitEvent
->Set();
74 while (!m_vecWindowMessages
.empty())
76 ThreadMessage
* pMsg
= m_vecWindowMessages
.front();
79 pMsg
->waitEvent
->Set();
82 m_vecWindowMessages
.pop();
86 int CApplicationMessenger::SendMsg(ThreadMessage
&& message
, bool wait
)
88 std::shared_ptr
<CEvent
> waitEvent
;
89 std::shared_ptr
<int> result
;
93 //Initialize result here as it's not needed for posted messages
94 message
.result
= std::make_shared
<int>(-1);
95 // check that we're not being called from our application thread, else we'll be waiting
97 if (m_guiThreadId
!= CThread::GetCurrentThreadId())
99 message
.waitEvent
= std::make_shared
<CEvent
>(true);
100 waitEvent
= message
.waitEvent
;
101 result
= message
.result
;
105 //OutputDebugString("Attempting to wait on a SendMessage() from our application thread will cause lockup!\n");
106 //OutputDebugString("Sending immediately\n");
107 ProcessMessage(&message
);
108 return *message
.result
;
116 ThreadMessage
* msg
= new ThreadMessage(std::move(message
));
118 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
120 if (msg
->dwMessage
== TMSG_GUI_MESSAGE
)
121 m_vecWindowMessages
.push(msg
);
123 m_vecMessages
.push(msg
);
124 lock
.unlock(); // this releases the lock on the vec of messages and
125 // allows the ProcessMessage to execute and therefore
126 // delete the message itself. Therefore any access
127 // of the message itself after this point constitutes
128 // a race condition (yarc - "yet another race condition")
130 if (waitEvent
) // ... it just so happens we have a spare reference to the
131 // waitEvent ... just for such contingencies :)
133 // ensure the thread doesn't hold the graphics lock
134 CWinSystemBase
* winSystem
= CServiceBroker::GetWinSystem();
135 //! @todo This won't really help as winSystem can die every single
136 // moment on shutdown. A shared ptr would be a more valid solution
137 // depending on the design dependencies.
140 CSingleExit
exit(winSystem
->GetGfxContext());
149 int CApplicationMessenger::SendMsg(uint32_t messageId
)
151 return SendMsg(ThreadMessage
{ messageId
}, true);
154 int CApplicationMessenger::SendMsg(uint32_t messageId
, int param1
, int param2
, void* payload
)
156 return SendMsg(ThreadMessage
{ messageId
, param1
, param2
, payload
}, true);
159 int CApplicationMessenger::SendMsg(uint32_t messageId
, int param1
, int param2
, void* payload
, std::string strParam
)
161 return SendMsg(ThreadMessage
{messageId
, param1
, param2
, payload
, std::move(strParam
),
162 std::vector
<std::string
>{}},
166 int CApplicationMessenger::SendMsg(uint32_t messageId
, int param1
, int param2
, void* payload
, std::string strParam
, std::vector
<std::string
> params
)
169 ThreadMessage
{messageId
, param1
, param2
, payload
, std::move(strParam
), std::move(params
)},
173 void CApplicationMessenger::PostMsg(uint32_t messageId
)
175 SendMsg(ThreadMessage
{ messageId
}, false);
178 void CApplicationMessenger::PostMsg(uint32_t messageId
, int64_t param3
)
180 SendMsg(ThreadMessage
{ messageId
, param3
}, false);
183 void CApplicationMessenger::PostMsg(uint32_t messageId
, int param1
, int param2
, void* payload
)
185 SendMsg(ThreadMessage
{ messageId
, param1
, param2
, payload
}, false);
188 void CApplicationMessenger::PostMsg(uint32_t messageId
, int param1
, int param2
, void* payload
, std::string strParam
)
190 SendMsg(ThreadMessage
{messageId
, param1
, param2
, payload
, std::move(strParam
),
191 std::vector
<std::string
>{}},
195 void CApplicationMessenger::PostMsg(uint32_t messageId
, int param1
, int param2
, void* payload
, std::string strParam
, std::vector
<std::string
> params
)
197 SendMsg(ThreadMessage
{messageId
, param1
, param2
, payload
, std::move(strParam
), std::move(params
)},
201 void CApplicationMessenger::ProcessMessages()
203 // process threadmessages
204 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
205 while (!m_vecMessages
.empty())
207 ThreadMessage
* pMsg
= m_vecMessages
.front();
208 //first remove the message from the queue, else the message could be processed more then once
211 //Leave here as the message might make another
212 //thread call processmessages or sendmessage
214 std::shared_ptr
<CEvent
> waitEvent
= pMsg
->waitEvent
;
215 lock
.unlock(); // <- see the large comment in SendMessage ^
217 ProcessMessage(pMsg
);
227 void CApplicationMessenger::ProcessMessage(ThreadMessage
*pMsg
)
229 //special case for this that we handle ourselves
230 if (pMsg
->dwMessage
== TMSG_CALLBACK
)
232 ThreadMessageCallback
*callback
= static_cast<ThreadMessageCallback
*>(pMsg
->lpVoid
);
233 callback
->callback(callback
->userptr
);
237 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
238 int mask
= pMsg
->dwMessage
& TMSG_MASK_MESSAGE
;
240 const auto it
= m_mapTargets
.find(mask
);
241 if (it
!= m_mapTargets
.end())
243 CSingleExit
exit(m_critSection
);
244 it
->second
->OnApplicationMessage(pMsg
);
247 CLog::LogF(LOGERROR
, "receiver {} is not defined", mask
);
250 void CApplicationMessenger::ProcessWindowMessages()
252 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
253 //message type is window, process window messages
254 while (!m_vecWindowMessages
.empty())
256 ThreadMessage
* pMsg
= m_vecWindowMessages
.front();
257 //first remove the message from the queue, else the message could be processed more then once
258 m_vecWindowMessages
.pop();
260 // leave here in case we make more thread messages from this one
262 std::shared_ptr
<CEvent
> waitEvent
= pMsg
->waitEvent
;
263 lock
.unlock(); // <- see the large comment in SendMessage ^
265 ProcessMessage(pMsg
);
274 void CApplicationMessenger::SendGUIMessage(const CGUIMessage
&message
, int windowID
, bool waitResult
)
276 ThreadMessage
tMsg(TMSG_GUI_MESSAGE
);
277 tMsg
.param1
= windowID
== WINDOW_INVALID
? 0 : windowID
;
278 tMsg
.lpVoid
= new CGUIMessage(message
);
279 SendMsg(std::move(tMsg
), waitResult
);
282 void CApplicationMessenger::RegisterReceiver(IMessageTarget
* target
)
284 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
285 m_mapTargets
.insert(std::make_pair(target
->GetMessageMask(), target
));
288 bool CApplicationMessenger::IsProcessThread() const
290 return m_processThreadId
== CThread::GetCurrentThreadId();