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 |