1*03ce13f7SAndroid Build Coastguard Worker // Copyright 2019 The SwiftShader Authors. All Rights Reserved. 2*03ce13f7SAndroid Build Coastguard Worker // 3*03ce13f7SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); 4*03ce13f7SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License. 5*03ce13f7SAndroid Build Coastguard Worker // You may obtain a copy of the License at 6*03ce13f7SAndroid Build Coastguard Worker // 7*03ce13f7SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0 8*03ce13f7SAndroid Build Coastguard Worker // 9*03ce13f7SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software 10*03ce13f7SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, 11*03ce13f7SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*03ce13f7SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and 13*03ce13f7SAndroid Build Coastguard Worker // limitations under the License. 14*03ce13f7SAndroid Build Coastguard Worker 15*03ce13f7SAndroid Build Coastguard Worker #ifndef VK_SEMAPHORE_EXTERNAL_LINUX_H_ 16*03ce13f7SAndroid Build Coastguard Worker #define VK_SEMAPHORE_EXTERNAL_LINUX_H_ 17*03ce13f7SAndroid Build Coastguard Worker 18*03ce13f7SAndroid Build Coastguard Worker #include "System/Linux/MemFd.hpp" 19*03ce13f7SAndroid Build Coastguard Worker #include "System/Memory.hpp" 20*03ce13f7SAndroid Build Coastguard Worker 21*03ce13f7SAndroid Build Coastguard Worker #include <errno.h> 22*03ce13f7SAndroid Build Coastguard Worker #include <pthread.h> 23*03ce13f7SAndroid Build Coastguard Worker #include <string.h> 24*03ce13f7SAndroid Build Coastguard Worker #include <sys/mman.h> 25*03ce13f7SAndroid Build Coastguard Worker 26*03ce13f7SAndroid Build Coastguard Worker // An external semaphore implementation for Linux, that uses memfd-backed 27*03ce13f7SAndroid Build Coastguard Worker // shared memory regions as the underlying implementation. The region contains 28*03ce13f7SAndroid Build Coastguard Worker // a single SharedSemaphore instance, which is a reference-counted semaphore 29*03ce13f7SAndroid Build Coastguard Worker // implementation based on a pthread process-shared mutex + condition variable 30*03ce13f7SAndroid Build Coastguard Worker // pair. 31*03ce13f7SAndroid Build Coastguard Worker // 32*03ce13f7SAndroid Build Coastguard Worker // This implementation works on any Linux system with at least kernel 3.17 33*03ce13f7SAndroid Build Coastguard Worker // (which should be sufficient for any not-so-recent Android system) and doesn't 34*03ce13f7SAndroid Build Coastguard Worker // require special libraries installed on the system. 35*03ce13f7SAndroid Build Coastguard Worker // 36*03ce13f7SAndroid Build Coastguard Worker // NOTE: This is not interoperable with other Linux ICDs that use Linux kernel 37*03ce13f7SAndroid Build Coastguard Worker // sync file objects (which correspond to 38*03ce13f7SAndroid Build Coastguard Worker // VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) instead. 39*03ce13f7SAndroid Build Coastguard Worker // 40*03ce13f7SAndroid Build Coastguard Worker 41*03ce13f7SAndroid Build Coastguard Worker // A process-shared semaphore implementation that can be stored in 42*03ce13f7SAndroid Build Coastguard Worker // a process-shared memory region. It also includes a reference count to 43*03ce13f7SAndroid Build Coastguard Worker // ensure it is only destroyed when the last reference to it is dropped. 44*03ce13f7SAndroid Build Coastguard Worker class SharedSemaphore 45*03ce13f7SAndroid Build Coastguard Worker { 46*03ce13f7SAndroid Build Coastguard Worker public: SharedSemaphore(bool initialValue)47*03ce13f7SAndroid Build Coastguard Worker SharedSemaphore(bool initialValue) 48*03ce13f7SAndroid Build Coastguard Worker : signaled(initialValue) 49*03ce13f7SAndroid Build Coastguard Worker { 50*03ce13f7SAndroid Build Coastguard Worker pthread_mutexattr_t mattr; 51*03ce13f7SAndroid Build Coastguard Worker pthread_mutexattr_init(&mattr); 52*03ce13f7SAndroid Build Coastguard Worker pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED); 53*03ce13f7SAndroid Build Coastguard Worker pthread_mutex_init(&mutex, &mattr); 54*03ce13f7SAndroid Build Coastguard Worker pthread_mutexattr_destroy(&mattr); 55*03ce13f7SAndroid Build Coastguard Worker 56*03ce13f7SAndroid Build Coastguard Worker pthread_condattr_t cattr; 57*03ce13f7SAndroid Build Coastguard Worker pthread_condattr_init(&cattr); 58*03ce13f7SAndroid Build Coastguard Worker pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED); 59*03ce13f7SAndroid Build Coastguard Worker pthread_cond_init(&cond, &cattr); 60*03ce13f7SAndroid Build Coastguard Worker pthread_condattr_destroy(&cattr); 61*03ce13f7SAndroid Build Coastguard Worker } 62*03ce13f7SAndroid Build Coastguard Worker ~SharedSemaphore()63*03ce13f7SAndroid Build Coastguard Worker ~SharedSemaphore() 64*03ce13f7SAndroid Build Coastguard Worker { 65*03ce13f7SAndroid Build Coastguard Worker pthread_cond_destroy(&cond); 66*03ce13f7SAndroid Build Coastguard Worker pthread_mutex_destroy(&mutex); 67*03ce13f7SAndroid Build Coastguard Worker } 68*03ce13f7SAndroid Build Coastguard Worker 69*03ce13f7SAndroid Build Coastguard Worker // Increment reference count. addRef()70*03ce13f7SAndroid Build Coastguard Worker void addRef() 71*03ce13f7SAndroid Build Coastguard Worker { 72*03ce13f7SAndroid Build Coastguard Worker pthread_mutex_lock(&mutex); 73*03ce13f7SAndroid Build Coastguard Worker ref_count++; 74*03ce13f7SAndroid Build Coastguard Worker pthread_mutex_unlock(&mutex); 75*03ce13f7SAndroid Build Coastguard Worker } 76*03ce13f7SAndroid Build Coastguard Worker 77*03ce13f7SAndroid Build Coastguard Worker // Decrement reference count and returns true iff it reaches 0. deref()78*03ce13f7SAndroid Build Coastguard Worker bool deref() 79*03ce13f7SAndroid Build Coastguard Worker { 80*03ce13f7SAndroid Build Coastguard Worker pthread_mutex_lock(&mutex); 81*03ce13f7SAndroid Build Coastguard Worker bool result = (--ref_count == 0); 82*03ce13f7SAndroid Build Coastguard Worker pthread_mutex_unlock(&mutex); 83*03ce13f7SAndroid Build Coastguard Worker return result; 84*03ce13f7SAndroid Build Coastguard Worker } 85*03ce13f7SAndroid Build Coastguard Worker wait()86*03ce13f7SAndroid Build Coastguard Worker void wait() 87*03ce13f7SAndroid Build Coastguard Worker { 88*03ce13f7SAndroid Build Coastguard Worker pthread_mutex_lock(&mutex); 89*03ce13f7SAndroid Build Coastguard Worker while(!signaled) 90*03ce13f7SAndroid Build Coastguard Worker { 91*03ce13f7SAndroid Build Coastguard Worker pthread_cond_wait(&cond, &mutex); 92*03ce13f7SAndroid Build Coastguard Worker } 93*03ce13f7SAndroid Build Coastguard Worker // From Vulkan 1.1.119 spec, section 6.4.2: 94*03ce13f7SAndroid Build Coastguard Worker // Unlike fences or events, the act of waiting for a semaphore also 95*03ce13f7SAndroid Build Coastguard Worker // unsignals that semaphore. 96*03ce13f7SAndroid Build Coastguard Worker signaled = false; 97*03ce13f7SAndroid Build Coastguard Worker pthread_mutex_unlock(&mutex); 98*03ce13f7SAndroid Build Coastguard Worker } 99*03ce13f7SAndroid Build Coastguard Worker 100*03ce13f7SAndroid Build Coastguard Worker // Just like wait() but never blocks. Returns true if the semaphore 101*03ce13f7SAndroid Build Coastguard Worker // was signaled (and reset by the function), or false otherwise. 102*03ce13f7SAndroid Build Coastguard Worker // Used to avoid using a background thread for waiting in the case 103*03ce13f7SAndroid Build Coastguard Worker // where the semaphore is already signaled. tryWait()104*03ce13f7SAndroid Build Coastguard Worker bool tryWait() 105*03ce13f7SAndroid Build Coastguard Worker { 106*03ce13f7SAndroid Build Coastguard Worker pthread_mutex_lock(&mutex); 107*03ce13f7SAndroid Build Coastguard Worker bool result = signaled; 108*03ce13f7SAndroid Build Coastguard Worker if(result) 109*03ce13f7SAndroid Build Coastguard Worker { 110*03ce13f7SAndroid Build Coastguard Worker signaled = false; 111*03ce13f7SAndroid Build Coastguard Worker } 112*03ce13f7SAndroid Build Coastguard Worker pthread_mutex_unlock(&mutex); 113*03ce13f7SAndroid Build Coastguard Worker return result; 114*03ce13f7SAndroid Build Coastguard Worker } 115*03ce13f7SAndroid Build Coastguard Worker signal()116*03ce13f7SAndroid Build Coastguard Worker void signal() 117*03ce13f7SAndroid Build Coastguard Worker { 118*03ce13f7SAndroid Build Coastguard Worker pthread_mutex_lock(&mutex); 119*03ce13f7SAndroid Build Coastguard Worker signaled = true; 120*03ce13f7SAndroid Build Coastguard Worker pthread_cond_broadcast(&cond); 121*03ce13f7SAndroid Build Coastguard Worker pthread_mutex_unlock(&mutex); 122*03ce13f7SAndroid Build Coastguard Worker } 123*03ce13f7SAndroid Build Coastguard Worker 124*03ce13f7SAndroid Build Coastguard Worker private: 125*03ce13f7SAndroid Build Coastguard Worker pthread_mutex_t mutex; 126*03ce13f7SAndroid Build Coastguard Worker pthread_cond_t cond; 127*03ce13f7SAndroid Build Coastguard Worker int ref_count = 1; 128*03ce13f7SAndroid Build Coastguard Worker bool signaled = false; 129*03ce13f7SAndroid Build Coastguard Worker }; 130*03ce13f7SAndroid Build Coastguard Worker 131*03ce13f7SAndroid Build Coastguard Worker namespace vk { 132*03ce13f7SAndroid Build Coastguard Worker 133*03ce13f7SAndroid Build Coastguard Worker class OpaqueFdExternalSemaphore : public BinarySemaphore::External 134*03ce13f7SAndroid Build Coastguard Worker { 135*03ce13f7SAndroid Build Coastguard Worker public: ~OpaqueFdExternalSemaphore()136*03ce13f7SAndroid Build Coastguard Worker ~OpaqueFdExternalSemaphore() { unmapRegion(); } 137*03ce13f7SAndroid Build Coastguard Worker 138*03ce13f7SAndroid Build Coastguard Worker // Initialize instance by creating a new shared memory region. init(bool initialState)139*03ce13f7SAndroid Build Coastguard Worker VkResult init(bool initialState) override 140*03ce13f7SAndroid Build Coastguard Worker { 141*03ce13f7SAndroid Build Coastguard Worker // Allocate or import the region's file descriptor. 142*03ce13f7SAndroid Build Coastguard Worker const size_t size = sw::memoryPageSize(); 143*03ce13f7SAndroid Build Coastguard Worker // To be exportable, the PosixSemaphore must be stored in a shared 144*03ce13f7SAndroid Build Coastguard Worker // memory region. 145*03ce13f7SAndroid Build Coastguard Worker static int counter = 0; 146*03ce13f7SAndroid Build Coastguard Worker char name[40]; 147*03ce13f7SAndroid Build Coastguard Worker snprintf(name, sizeof(name), "SwiftShader.Semaphore.%d", ++counter); 148*03ce13f7SAndroid Build Coastguard Worker if(!memfd.allocate(name, size)) 149*03ce13f7SAndroid Build Coastguard Worker { 150*03ce13f7SAndroid Build Coastguard Worker TRACE("memfd.allocate() returned %s", strerror(errno)); 151*03ce13f7SAndroid Build Coastguard Worker return VK_ERROR_INITIALIZATION_FAILED; 152*03ce13f7SAndroid Build Coastguard Worker } 153*03ce13f7SAndroid Build Coastguard Worker if(!mapRegion(size, true, initialState)) 154*03ce13f7SAndroid Build Coastguard Worker return VK_ERROR_INITIALIZATION_FAILED; 155*03ce13f7SAndroid Build Coastguard Worker 156*03ce13f7SAndroid Build Coastguard Worker return VK_SUCCESS; 157*03ce13f7SAndroid Build Coastguard Worker } 158*03ce13f7SAndroid Build Coastguard Worker 159*03ce13f7SAndroid Build Coastguard Worker // Import an existing semaphore through its file descriptor. importOpaqueFd(int fd)160*03ce13f7SAndroid Build Coastguard Worker VkResult importOpaqueFd(int fd) override 161*03ce13f7SAndroid Build Coastguard Worker { 162*03ce13f7SAndroid Build Coastguard Worker unmapRegion(); 163*03ce13f7SAndroid Build Coastguard Worker memfd.importFd(fd); 164*03ce13f7SAndroid Build Coastguard Worker if(!mapRegion(sw::memoryPageSize(), false, false)) 165*03ce13f7SAndroid Build Coastguard Worker return VK_ERROR_INITIALIZATION_FAILED; 166*03ce13f7SAndroid Build Coastguard Worker 167*03ce13f7SAndroid Build Coastguard Worker return VK_SUCCESS; 168*03ce13f7SAndroid Build Coastguard Worker } 169*03ce13f7SAndroid Build Coastguard Worker 170*03ce13f7SAndroid Build Coastguard Worker // Export the current semaphore as a duplicated file descriptor to the same 171*03ce13f7SAndroid Build Coastguard Worker // region. This can be consumed by importFd() running in a different 172*03ce13f7SAndroid Build Coastguard Worker // process. exportOpaqueFd(int * pFd)173*03ce13f7SAndroid Build Coastguard Worker VkResult exportOpaqueFd(int *pFd) override 174*03ce13f7SAndroid Build Coastguard Worker { 175*03ce13f7SAndroid Build Coastguard Worker int fd = memfd.exportFd(); 176*03ce13f7SAndroid Build Coastguard Worker if(fd < 0) 177*03ce13f7SAndroid Build Coastguard Worker { 178*03ce13f7SAndroid Build Coastguard Worker return VK_ERROR_INVALID_EXTERNAL_HANDLE; 179*03ce13f7SAndroid Build Coastguard Worker } 180*03ce13f7SAndroid Build Coastguard Worker *pFd = fd; 181*03ce13f7SAndroid Build Coastguard Worker return VK_SUCCESS; 182*03ce13f7SAndroid Build Coastguard Worker } 183*03ce13f7SAndroid Build Coastguard Worker wait()184*03ce13f7SAndroid Build Coastguard Worker void wait() override 185*03ce13f7SAndroid Build Coastguard Worker { 186*03ce13f7SAndroid Build Coastguard Worker semaphore->wait(); 187*03ce13f7SAndroid Build Coastguard Worker } 188*03ce13f7SAndroid Build Coastguard Worker tryWait()189*03ce13f7SAndroid Build Coastguard Worker bool tryWait() override 190*03ce13f7SAndroid Build Coastguard Worker { 191*03ce13f7SAndroid Build Coastguard Worker return semaphore->tryWait(); 192*03ce13f7SAndroid Build Coastguard Worker } 193*03ce13f7SAndroid Build Coastguard Worker signal()194*03ce13f7SAndroid Build Coastguard Worker void signal() override 195*03ce13f7SAndroid Build Coastguard Worker { 196*03ce13f7SAndroid Build Coastguard Worker semaphore->signal(); 197*03ce13f7SAndroid Build Coastguard Worker } 198*03ce13f7SAndroid Build Coastguard Worker 199*03ce13f7SAndroid Build Coastguard Worker private: unmapRegion()200*03ce13f7SAndroid Build Coastguard Worker void unmapRegion() 201*03ce13f7SAndroid Build Coastguard Worker { 202*03ce13f7SAndroid Build Coastguard Worker if(semaphore) 203*03ce13f7SAndroid Build Coastguard Worker { 204*03ce13f7SAndroid Build Coastguard Worker if(semaphore->deref()) 205*03ce13f7SAndroid Build Coastguard Worker { 206*03ce13f7SAndroid Build Coastguard Worker semaphore->~SharedSemaphore(); 207*03ce13f7SAndroid Build Coastguard Worker } 208*03ce13f7SAndroid Build Coastguard Worker memfd.unmap(semaphore, sw::memoryPageSize()); 209*03ce13f7SAndroid Build Coastguard Worker memfd.close(); 210*03ce13f7SAndroid Build Coastguard Worker semaphore = nullptr; 211*03ce13f7SAndroid Build Coastguard Worker } 212*03ce13f7SAndroid Build Coastguard Worker } 213*03ce13f7SAndroid Build Coastguard Worker 214*03ce13f7SAndroid Build Coastguard Worker // Remap the shared region and setup the semaphore or increment its reference count. mapRegion(size_t size,bool needsInitialization,bool initialValue)215*03ce13f7SAndroid Build Coastguard Worker bool mapRegion(size_t size, bool needsInitialization, bool initialValue) 216*03ce13f7SAndroid Build Coastguard Worker { 217*03ce13f7SAndroid Build Coastguard Worker // Map the region into memory and point the semaphore to it. 218*03ce13f7SAndroid Build Coastguard Worker void *addr = memfd.mapReadWrite(0, size); 219*03ce13f7SAndroid Build Coastguard Worker if(!addr) 220*03ce13f7SAndroid Build Coastguard Worker { 221*03ce13f7SAndroid Build Coastguard Worker TRACE("mmap() failed: %s", strerror(errno)); 222*03ce13f7SAndroid Build Coastguard Worker return false; 223*03ce13f7SAndroid Build Coastguard Worker } 224*03ce13f7SAndroid Build Coastguard Worker semaphore = reinterpret_cast<SharedSemaphore *>(addr); 225*03ce13f7SAndroid Build Coastguard Worker if(needsInitialization) 226*03ce13f7SAndroid Build Coastguard Worker { 227*03ce13f7SAndroid Build Coastguard Worker new(semaphore) SharedSemaphore(initialValue); 228*03ce13f7SAndroid Build Coastguard Worker } 229*03ce13f7SAndroid Build Coastguard Worker else 230*03ce13f7SAndroid Build Coastguard Worker { 231*03ce13f7SAndroid Build Coastguard Worker semaphore->addRef(); 232*03ce13f7SAndroid Build Coastguard Worker } 233*03ce13f7SAndroid Build Coastguard Worker return true; 234*03ce13f7SAndroid Build Coastguard Worker } 235*03ce13f7SAndroid Build Coastguard Worker 236*03ce13f7SAndroid Build Coastguard Worker LinuxMemFd memfd; 237*03ce13f7SAndroid Build Coastguard Worker SharedSemaphore *semaphore = nullptr; 238*03ce13f7SAndroid Build Coastguard Worker }; 239*03ce13f7SAndroid Build Coastguard Worker 240*03ce13f7SAndroid Build Coastguard Worker } // namespace vk 241*03ce13f7SAndroid Build Coastguard Worker 242*03ce13f7SAndroid Build Coastguard Worker #endif // VK_SEMAPHORE_EXTERNAL_LINUX_H_ 243