| OLD | NEW |
| (Empty) |
| 1 // Copyright 2003-2009 Google Inc. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 // ======================================================================== | |
| 15 // | |
| 16 // Synchronization functions | |
| 17 | |
| 18 #include "omaha/base/single_instance.h" | |
| 19 #include "omaha/base/constants.h" | |
| 20 #include "omaha/base/debug.h" | |
| 21 #include "omaha/base/logging.h" | |
| 22 #include "omaha/base/scoped_any.h" | |
| 23 #include "omaha/base/synchronized.h" | |
| 24 #include "omaha/base/utils.h" | |
| 25 | |
| 26 namespace omaha { | |
| 27 | |
| 28 // Check to see whether an instance is already running across all sessions. | |
| 29 // If not, enter single instance protection. The user must call Shutdown() | |
| 30 // on that SingleInstance once single instance protection is no longer needed. | |
| 31 bool SingleInstance::StartupSingleInstance(const TCHAR* id) { | |
| 32 ASSERT1(id); | |
| 33 | |
| 34 bool already_running = false, already_running_in_different_session = false; | |
| 35 HRESULT hr = Startup(id, | |
| 36 &already_running, | |
| 37 &already_running_in_different_session); | |
| 38 ASSERT(SUCCEEDED(hr), (_T(""))); | |
| 39 | |
| 40 return already_running || already_running_in_different_session; | |
| 41 } | |
| 42 | |
| 43 // Check to see whether an instance is already running in this session. If not, | |
| 44 // enter session-only single instance protection. The user must call Shutdown() | |
| 45 // on that SingleInstance once single instance protection is no longer needed. | |
| 46 bool SingleInstance::StartupSingleSessionInstance(const TCHAR* id) { | |
| 47 ASSERT1(id); | |
| 48 | |
| 49 bool already_running = false; | |
| 50 HRESULT hr = Startup(id, &already_running, NULL); | |
| 51 ASSERT(SUCCEEDED(hr), (_T(""))); | |
| 52 | |
| 53 return already_running; | |
| 54 } | |
| 55 | |
| 56 // Startup a single instance protection. The user must call Shutdown() on | |
| 57 // that SingleInstance once the single instance protection is no longer needed. | |
| 58 // | |
| 59 // Returns whether or not the process is already running | |
| 60 // already_running means "already running in same session". | |
| 61 // already_running_in_different_session means "already running on machine" | |
| 62 HRESULT SingleInstance::Startup(const TCHAR* id, | |
| 63 bool* already_running, | |
| 64 bool* already_running_in_different_session) { | |
| 65 ASSERT1(id); | |
| 66 ASSERT1(already_running); | |
| 67 | |
| 68 CString mutex_id; | |
| 69 | |
| 70 // Use two mutexes: one to check for being the only instance in this | |
| 71 // session, and one for being the only instance in any terminal session. | |
| 72 // Only create (and check) the global mutex for one-per-machine check if | |
| 73 // the result is asked for. | |
| 74 // We don't actually obtain ownership of the mutex | |
| 75 // For information on the "Local" and "Global" namespace prefixes, see MSDN | |
| 76 // article "Kernel Object Namespaces". | |
| 77 | |
| 78 // Create a user level mutex | |
| 79 CreateSyncId(id, SYNC_USER, &mutex_id); | |
| 80 RET_IF_FAILED(CreateInstanceMutex(mutex_id, | |
| 81 &user_mutex_handle_, | |
| 82 already_running)); | |
| 83 | |
| 84 // Create a global mutex | |
| 85 if (already_running_in_different_session) { | |
| 86 CreateSyncId(id, SYNC_GLOBAL, &mutex_id); | |
| 87 RET_IF_FAILED(CreateInstanceMutex(mutex_id, | |
| 88 &global_mutex_handle_, | |
| 89 already_running_in_different_session)); | |
| 90 } | |
| 91 | |
| 92 return S_OK; | |
| 93 } | |
| 94 | |
| 95 // Create a mutex | |
| 96 HRESULT SingleInstance::CreateInstanceMutex(const TCHAR* mutex_id, | |
| 97 HANDLE* mutex_handle, | |
| 98 bool* already_running) { | |
| 99 ASSERT1(mutex_id && *mutex_id); | |
| 100 ASSERT1(mutex_handle); | |
| 101 ASSERT1(already_running); | |
| 102 | |
| 103 *already_running = false; | |
| 104 | |
| 105 *mutex_handle = ::CreateMutex(NULL, false, mutex_id); | |
| 106 DWORD last_error = ::GetLastError(); | |
| 107 | |
| 108 // We check for both values because we sometimes see access | |
| 109 // denied. We expect this to mean that the mutex was created by a | |
| 110 // different set of user credentials, which shouldn't happen under | |
| 111 // normal circumstances in our applications, but in fact we did | |
| 112 // see it happen. | |
| 113 if (last_error == ERROR_ALREADY_EXISTS || last_error == ERROR_ACCESS_DENIED) { | |
| 114 *already_running = true; | |
| 115 return S_OK; | |
| 116 } | |
| 117 | |
| 118 if (*mutex_handle == NULL) { | |
| 119 HRESULT hr = HRESULT_FROM_WIN32(last_error); | |
| 120 ASSERT(false, (_T("[SingleInstance::CreateInstanceMutex]") | |
| 121 _T("[failed to create mutex][%s][0x%x]"), mutex_id, hr)); | |
| 122 return hr; | |
| 123 } | |
| 124 | |
| 125 return S_OK; | |
| 126 } | |
| 127 | |
| 128 // Shutdown a single instance protection | |
| 129 HRESULT SingleInstance::Shutdown() { | |
| 130 if (user_mutex_handle_) { | |
| 131 VERIFY(::CloseHandle(user_mutex_handle_), (_T(""))); | |
| 132 user_mutex_handle_ = NULL; | |
| 133 } | |
| 134 | |
| 135 if (global_mutex_handle_) { | |
| 136 VERIFY(::CloseHandle(global_mutex_handle_), (_T(""))); | |
| 137 global_mutex_handle_ = NULL; | |
| 138 } | |
| 139 | |
| 140 return S_OK; | |
| 141 } | |
| 142 | |
| 143 // Check to see whether an instance is already running | |
| 144 HRESULT SingleInstance::CheckAlreadyRunning( | |
| 145 const TCHAR* id, | |
| 146 bool* already_running, | |
| 147 bool* already_running_in_different_session) { | |
| 148 ASSERT1(id); | |
| 149 ASSERT1(already_running); | |
| 150 | |
| 151 CString mutex_id; | |
| 152 | |
| 153 // Open a user level mutex | |
| 154 CreateSyncId(id, SYNC_USER, &mutex_id); | |
| 155 RET_IF_FAILED(OpenInstanceMutex(mutex_id, already_running)); | |
| 156 | |
| 157 // Open a global mutex | |
| 158 if (already_running_in_different_session) { | |
| 159 CreateSyncId(id, SYNC_GLOBAL, &mutex_id); | |
| 160 RET_IF_FAILED(OpenInstanceMutex(mutex_id, | |
| 161 already_running_in_different_session)); | |
| 162 } | |
| 163 | |
| 164 return S_OK; | |
| 165 } | |
| 166 | |
| 167 // Open a mutex | |
| 168 HRESULT SingleInstance::OpenInstanceMutex(const TCHAR* mutex_id, | |
| 169 bool* already_running) { | |
| 170 ASSERT1(mutex_id && *mutex_id); | |
| 171 ASSERT1(already_running); | |
| 172 | |
| 173 *already_running = false; | |
| 174 | |
| 175 scoped_handle mutex_handle(::OpenMutex(NULL, false, mutex_id)); | |
| 176 DWORD last_error = ::GetLastError(); | |
| 177 | |
| 178 if (get(mutex_handle) || last_error == ERROR_ACCESS_DENIED) { | |
| 179 UTIL_LOG(L3, (_T("[SingleInstance::OpenInstanceMutex]") | |
| 180 _T("[already running][0x%x]"), last_error)); | |
| 181 *already_running = true; | |
| 182 return S_OK; | |
| 183 } | |
| 184 | |
| 185 if (last_error != ERROR_FILE_NOT_FOUND) { | |
| 186 HRESULT hr = HRESULT_FROM_WIN32(last_error); | |
| 187 ASSERT(false, (_T("[SingleInstance::OpenInstanceMutex]") | |
| 188 _T("[failed to open mutex][%s][0x%x]"), mutex_id, hr)); | |
| 189 return hr; | |
| 190 } | |
| 191 | |
| 192 return S_OK; | |
| 193 } | |
| 194 | |
| 195 } // namespace omaha | |
| 196 | |
| OLD | NEW |