| 83 | } |
| 84 | |
| 85 | bool InitializeServerPipe() { |
| 86 | auto ServerFolder = FEXServerClient::GetServerLockFolder(); |
| 87 | |
| 88 | std::error_code ec {}; |
| 89 | if (!std::filesystem::exists(ServerFolder, ec)) { |
| 90 | // Doesn't exist, create the the folder as a user convenience |
| 91 | if (!std::filesystem::create_directories(ServerFolder, ec)) { |
| 92 | LogMan::Msg::EFmt("Couldn't create server pipe folder at: {}", ServerFolder); |
| 93 | return false; |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | auto ServerLockPath = FEXServerClient::GetServerLockFile(); |
| 98 | |
| 99 | // Now this is some tricky locking logic to ensure that we only ever have one server running |
| 100 | // The logic is as follows: |
| 101 | // - Try to make the lock file |
| 102 | // - If Exists then check to see if it is a stale handle |
| 103 | // - Stale checking means opening the file that we know exists |
| 104 | // - Then we try getting a write lock |
| 105 | // - If we fail to get the write lock, then leave |
| 106 | // - Otherwise continue down the codepath and degrade to read lock |
| 107 | // - Else try to acquire a write lock to ensure only one FEXServer exists |
| 108 | // |
| 109 | // - Once a write lock is acquired, downgrade it to a read lock |
| 110 | // - This ensures that future FEXServers won't race to create multiple read locks |
| 111 | int Ret = open(ServerLockPath.c_str(), O_RDWR | O_CREAT | O_CLOEXEC | O_EXCL, USER_PERMS); |
| 112 | ServerLockFD = Ret; |
| 113 | |
| 114 | if (Ret == -1 && errno == EEXIST) { |
| 115 | // If the lock exists then it might be a stale connection. |
| 116 | // Check the lock status to see if another process is still alive. |
| 117 | ServerLockFD = open(ServerLockPath.c_str(), O_RDWR | O_CLOEXEC, USER_PERMS); |
| 118 | if (ServerLockFD != -1) { |
| 119 | // Now that we have opened the file, try to get a write lock. |
| 120 | flock lk { |
| 121 | .l_type = F_WRLCK, |
| 122 | .l_whence = SEEK_SET, |
| 123 | .l_start = 0, |
| 124 | .l_len = 0, |
| 125 | }; |
| 126 | Ret = fcntl(ServerLockFD, F_SETLK, &lk); |
| 127 | |
| 128 | if (Ret != -1) { |
| 129 | // Write lock was gained, we can now continue onward. |
| 130 | } else { |
| 131 | // We couldn't get a write lock, this means that another process already owns a lock on the lock |
| 132 | close(ServerLockFD); |
| 133 | ServerLockFD = -1; |
| 134 | return false; |
| 135 | } |
| 136 | } else { |
| 137 | // File couldn't get opened even though it existed? |
| 138 | // Must have raced something here. |
| 139 | return false; |
| 140 | } |
| 141 | } else if (Ret == -1) { |
| 142 | // Unhandled error. |
no test coverage detected