|
25 | 25 | #include "ARA_Library/Dispatch/ARAPlugInDispatch.h" |
26 | 26 | #include "ARA_Library/Dispatch/ARAHostDispatch.h" |
27 | 27 |
|
| 28 | +#include <condition_variable> |
28 | 29 | #include <cstring> |
29 | 30 | #include <map> |
| 31 | +#include <mutex> |
30 | 32 | #include <set> |
31 | 33 | #include <string> |
32 | 34 |
|
@@ -1296,6 +1298,115 @@ struct RemoteFactory |
1296 | 1298 | std::map<std::string, RemoteFactory> _factories {}; |
1297 | 1299 |
|
1298 | 1300 |
|
| 1301 | +class DistributedMainThreadLock |
| 1302 | +{ |
| 1303 | +private: |
| 1304 | +// for some reason, Xcode thinks this is no constant expression... |
| 1305 | +// static constexpr ARAIPCConnectionRef _dummyLocalConnectionRef { reinterpret_cast<ARAIPCConnectionRef> (-1) }; |
| 1306 | + const ARAIPCConnectionRef _dummyLocalConnectionRef { reinterpret_cast<ARAIPCConnectionRef> (-1) }; |
| 1307 | + |
| 1308 | + template<bool tryLock> |
| 1309 | + bool _lockImpl (ARAIPCConnectionRef connectionRef) |
| 1310 | + { |
| 1311 | + std::unique_lock <std::mutex> lock { _lock }; |
| 1312 | + if (_lockingConnection == nullptr) |
| 1313 | + { |
| 1314 | + ARA_INTERNAL_ASSERT (_recursionCount == 0); |
| 1315 | + _lockingConnection = connectionRef; |
| 1316 | + return true; |
| 1317 | + } |
| 1318 | + else if (_lockingConnection == connectionRef) |
| 1319 | + { |
| 1320 | + ++_recursionCount; |
| 1321 | + return true; |
| 1322 | + } |
| 1323 | + else |
| 1324 | + { |
| 1325 | + if (tryLock) |
| 1326 | + return false; |
| 1327 | + |
| 1328 | + _condition.wait (lock, [this, connectionRef] |
| 1329 | + { return (_lockingConnection == nullptr) || (_lockingConnection == connectionRef); }); |
| 1330 | + if (_lockingConnection == nullptr) |
| 1331 | + { |
| 1332 | + ARA_INTERNAL_ASSERT (_recursionCount == 0); |
| 1333 | + _lockingConnection = connectionRef; |
| 1334 | + } |
| 1335 | + else |
| 1336 | + { |
| 1337 | + ARA_INTERNAL_ASSERT (_lockingConnection == connectionRef); |
| 1338 | + ++_recursionCount; |
| 1339 | + } |
| 1340 | + return true; |
| 1341 | + } |
| 1342 | + } |
| 1343 | + |
| 1344 | + void _unlockImpl (ARAIPCConnectionRef connectionRef) |
| 1345 | + { |
| 1346 | + std::unique_lock <std::mutex> lock { _lock }; |
| 1347 | + ARA_INTERNAL_ASSERT (_lockingConnection == connectionRef); |
| 1348 | + if (_recursionCount > 0) |
| 1349 | + { |
| 1350 | + --_recursionCount; |
| 1351 | + } |
| 1352 | + else |
| 1353 | + { |
| 1354 | + _lockingConnection = nullptr; |
| 1355 | + _condition.notify_all (); |
| 1356 | + } |
| 1357 | + } |
| 1358 | + |
| 1359 | +public: |
| 1360 | + DistributedMainThreadLock () = default; |
| 1361 | + |
| 1362 | + void lockFromLocalMainThread () |
| 1363 | + { |
| 1364 | + _lockImpl<false> (_dummyLocalConnectionRef); |
| 1365 | + ARA_IPC_LOG ("distributed main thread was locked from host."); |
| 1366 | + } |
| 1367 | + bool tryLockFromLocalMainThread () |
| 1368 | + { |
| 1369 | + const auto result { _lockImpl<true> (_dummyLocalConnectionRef) }; |
| 1370 | + if (result) |
| 1371 | + ARA_IPC_LOG ("distributed main thread was try-locked from host."); |
| 1372 | + else |
| 1373 | + ARA_IPC_LOG ("distributed main thread try-lock from host failed."); |
| 1374 | + return result; |
| 1375 | + } |
| 1376 | + void unlockFromLocalMainThread () |
| 1377 | + { |
| 1378 | + ARA_IPC_LOG ("distributed main thread will be unlocked from host."); |
| 1379 | + _unlockImpl (_dummyLocalConnectionRef); |
| 1380 | + } |
| 1381 | + |
| 1382 | + void lockFromRemoteMainThread (ARAIPCConnectionRef connectionRef) |
| 1383 | + { |
| 1384 | + _lockImpl<false> (connectionRef); |
| 1385 | + ARA_IPC_LOG ("distributed main thread was locked from remote."); |
| 1386 | + } |
| 1387 | + bool tryLockFromRemoteMainThread (ARAIPCConnectionRef connectionRef) |
| 1388 | + { |
| 1389 | + const auto result { _lockImpl<true> (connectionRef) }; |
| 1390 | + if (result) |
| 1391 | + ARA_IPC_LOG ("distributed main thread was try-locked from remote."); |
| 1392 | + else |
| 1393 | + ARA_IPC_LOG ("distributed main thread try-lock from remote failed."); |
| 1394 | + return result; |
| 1395 | + } |
| 1396 | + void unlockFromRemoteMainThread (ARAIPCConnectionRef connectionRef) |
| 1397 | + { |
| 1398 | + ARA_IPC_LOG ("distributed main thread will be unlocked from remote."); |
| 1399 | + _unlockImpl (connectionRef); |
| 1400 | + } |
| 1401 | + |
| 1402 | +private: |
| 1403 | + std::mutex _lock; |
| 1404 | + std::condition_variable _condition; |
| 1405 | + ARAIPCConnectionRef _lockingConnection { nullptr }; |
| 1406 | + int _recursionCount { 0 }; |
| 1407 | +} _distributedMainThreadLock {}; |
| 1408 | + |
| 1409 | + |
1299 | 1410 | /*******************************************************************************/ |
1300 | 1411 |
|
1301 | 1412 | } // namespace ProxyPlugInImpl |
@@ -1433,6 +1544,20 @@ ARABool ARAIPCProxyPlugInCurrentThreadActsAsMainThread () |
1433 | 1544 | return (Connection::currentThreadActsAsMainThread ()) ? kARATrue : kARAFalse; |
1434 | 1545 | } |
1435 | 1546 |
|
| 1547 | +void ARAIPCProxyPlugInLockDistributedMainThread () |
| 1548 | +{ |
| 1549 | + _distributedMainThreadLock.lockFromLocalMainThread (); |
| 1550 | +} |
| 1551 | + |
| 1552 | +ARABool ARAIPCProxyPlugInTryLockDistributedMainThread () |
| 1553 | +{ |
| 1554 | + return (_distributedMainThreadLock.tryLockFromLocalMainThread ()) ? kARATrue : kARAFalse; |
| 1555 | +} |
| 1556 | + |
| 1557 | +void ARAIPCProxyPlugInUnlockDistributedMainThread () |
| 1558 | +{ |
| 1559 | + _distributedMainThreadLock.unlockFromLocalMainThread (); |
| 1560 | +} |
1436 | 1561 |
|
1437 | 1562 | /*******************************************************************************/ |
1438 | 1563 |
|
@@ -1841,6 +1966,19 @@ void ProxyPlugIn::handleReceivedMessage (const MessageID messageID, const Messag |
1841 | 1966 |
|
1842 | 1967 | documentController->getHostPlaybackController ()->requestEnableCycle (enable != kARAFalse); |
1843 | 1968 | } |
| 1969 | + else if (messageID == kLockDistributedMainThreadMethodID) |
| 1970 | + { |
| 1971 | + _distributedMainThreadLock.lockFromRemoteMainThread (toIPCRef (getConnection ())); |
| 1972 | + } |
| 1973 | + else if (messageID == kTryLockDistributedMainThreadMethodID) |
| 1974 | + { |
| 1975 | + auto result { _distributedMainThreadLock.tryLockFromRemoteMainThread (toIPCRef (getConnection ())) }; |
| 1976 | + encodeReply (replyEncoder, (result) ? kARATrue : kARAFalse); |
| 1977 | + } |
| 1978 | + else if (messageID == kUnlockDistributedMainThreadMethodID) |
| 1979 | + { |
| 1980 | + _distributedMainThreadLock.unlockFromRemoteMainThread (toIPCRef (getConnection ())); |
| 1981 | + } |
1844 | 1982 | else |
1845 | 1983 | { |
1846 | 1984 | ARA_INTERNAL_ASSERT (false && "unhandled message ID"); |
|
0 commit comments