Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(321)

Side by Side Diff: base/shared_memory_ptr.h

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/shared_any.h ('k') | base/shell.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2004-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 // Defines template class used to share data
17 // between processes.
18 //
19
20 #ifndef OMAHA_COMMON_SHARED_MEMORY_PTR_H__
21 #define OMAHA_COMMON_SHARED_MEMORY_PTR_H__
22
23 #include "base/debug.h"
24 #include "base/singleton.h"
25 #include "base/system_info.h"
26 #include "base/vista_utils.h"
27
28 namespace omaha {
29
30 // SharedMemoryPtr class is designed to allow seamless data sharing process boun daries.
31 // All the data passed as a template parameter will be shared between processes.
32 // Very important to remember that for now - all shared data should be on stack.
33 // For example if the class A had stl vector as a member, the members of the vec tor
34 // would be allocated not from shared memory and therefore will not be shared.
35 // That could be solved with allocators, but for now we don't need that.
36 //
37 // Here is a typical example of usage:
38 // Class A {
39 // int i_;
40 // double d_;
41 // .......
42 // ........
43 //
44 // public:
45 // set_double(double d){d_=d;}
46 // double get_double(){return d_};
47 //
48 // };
49 //
50 // ... Prosess one...
51 // SharedMemoryPtr<A> spA("ABC");
52 // if (!spA)
53 // return false;
54 //
55 // spA->set_double(3.14);
56 //
57 // ... Process two ...
58 //
59 //
60 // SharedMemoryPtr<A> spA1("ABC");
61 // if (!spA1)
62 // return false;
63 //
64 // process two will see the value set by process one.
65 // it will be 3.14
66 // double d = spA1->get_double();
67 //
68
69 // You should implement a class member of SystemSharedData if the data you want
70 // to share is several hundred bytes. Always try this approach first before you implement
71 // new class that is derived from SharedMemoryPtr. The main difference is that S haredMemoryPtr
72 // will allocate a least page of shared memory. If your class is just a member o f SystemSharedData
73 // memory mapped file will be shared between members. It is just more efficient.
74 // Look in system_shared_data.h , shared_data_member.h, and system_shared_data_m embers.h
75 // for more details.
76
77 // Forward declaration.
78 template <typename LockType, typename T> class SharedMemoryPtr;
79
80 // During several code reviews it has been noticed that the same error gets repe ated over and over.
81 // People create SharedMemoryPtr<SomeData>. And than the access to member functi ons of SomeData
82 // is not synchronized by __mutexBlock or __mutexScope. So we need to somehow fi nd a way to make
83 // automatic syncronization whenever people access shared data methods or membe rs.
84 // Since by design the only way we can acess shared data is through operator -> of SharedMemoryPtr
85 // we need to somehow invoke synchronization at the time of access.
86 // We can implement this mainly because of the mechanics of operator-> dictated by C++ standard.
87 // When you apply operator-> to a type that's not a built-in pointer, the compil er does an interesting thing.
88 // After looking up and applying the user-defined operator-> to that type, it ap plies operator-> again to the result.
89 // The compiler keeps doing this recursively until it reaches a pointer to a bui lt-in type, and only then proceeds with member access.
90 // It follows that a SharedMemoryPtr<T> operator-> does not have to return a poi nter.
91 // It can return an object that in turn implements operator->, without changing the use syntax.
92 // So we can implement: pre- and postfunction calls. (See Stroustrup 2000)
93 // If you return an object of some type X
94 // by value from operator->, the sequence of execution is as follows:
95 // 1. Constructor of type X
96 // 2. X::operator-> called; returns a pointer to an object of type T of SharedM emoryPtr
97 // 3. Member access
98 // 4. Destructor of X
99 // In a nutshell, we have a way of implementing locked function calls.
100
101 template <typename LockType, typename T>
102 class SharedDataLockingProxy {
103 public:
104 // Lock on construction.
105 SharedDataLockingProxy(SharedMemoryPtr<LockType, T> * mem_ptr, T* shared_data)
106 : mem_ptr_(mem_ptr), shared_data_(shared_data) {
107 mem_ptr_->Lock();
108 }
109 // Unlock on destruction.
110 ~SharedDataLockingProxy() {
111 mem_ptr_->Unlock();
112 }
113 // operator
114 T* operator->() const {
115 ASSERT(shared_data_ != NULL, (L"NULL object pointer being dereferenced"));
116 return shared_data_;
117 }
118 private:
119 SharedDataLockingProxy& operator=(const SharedDataLockingProxy&);
120 SharedMemoryPtr<LockType, T>* mem_ptr_;
121 T* shared_data_;
122 // To allow this implicit locking - copy constructor must be
123 // enabled. hence, no DISALLOW_EVIL_CONSTRUCTORS
124 };
125
126 template <typename LockType, typename T> class SharedMemoryPtr
127 : public LockType {
128 // Handle to disk file if we're backing this shared memory by a file
129 HANDLE file_;
130 // Local handle to file mapping.
131 HANDLE file_mapping_;
132 // pointer to a view.
133 T* data_;
134 // If the first time creation can do some initialization.
135 bool first_instance_;
136 public:
137 // The heart of the whole idea. Points to shared memrory
138 // instead of the beginning of the class.
139 SharedDataLockingProxy<LockType, T> operator->() {
140 return SharedDataLockingProxy<LockType, T>(this, data_);
141 }
142 // To check after creation.
143 // For example:
144 // SharedMemoryPtr<GLock, SomeClass> sm;
145 // if (sm)
146 // { do whatever you want}
147 // else
148 // {error reporting}
149 operator bool() const {return ((file_mapping_ != NULL) && (data_ != NULL));}
150
151 // Initialize memory mapped file and sync mechanics.
152 // by calling InitializeSharedAccess
153 SharedMemoryPtr(const CString& name,
154 LPSECURITY_ATTRIBUTES sa,
155 LPSECURITY_ATTRIBUTES sa_mutex,
156 bool read_only)
157 : file_(INVALID_HANDLE_VALUE),
158 file_mapping_(NULL),
159 data_(NULL) {
160 HRESULT hr = InitializeSharedAccess(name, false, sa, sa_mutex, read_only);
161 if (FAILED(hr)) {
162 UTIL_LOG(LE, (_T("InitializeSharedAccess failed [%s][%s][0x%x]"),
163 name, read_only ? _T("R") : _T("RW"), hr));
164 }
165 }
166
167 // Use this constructor if you want to back the shared memory by a file.
168 // NOTE: if using a persistent shared memory, every object with this same
169 // name should be persistent. Otherwise, the objects marked as
170 // non-persistent will lead to InitializeSharedData called again if
171 // they are instantiated before the ones marked as persistent.
172 SharedMemoryPtr(bool persist,
173 LPSECURITY_ATTRIBUTES sa,
174 LPSECURITY_ATTRIBUTES sa_mutex,
175 bool read_only)
176 : file_(INVALID_HANDLE_VALUE),
177 file_mapping_(NULL),
178 data_(NULL) {
179 // Each shared data must implement GetFileName() to use this c-tor. The
180 // implementation should be:
181 // const CString GetFileName() const {return L"C:\\directory\file";}
182 // This is purposedly different from GetSharedName, so that the user is
183 // well aware that a file name is expected, not a mutex name.
184 HRESULT hr = InitializeSharedAccess(data_->GetFileName(),
185 persist,
186 sa,
187 sa_mutex,
188 read_only);
189 if (FAILED(hr)) {
190 UTIL_LOG(LE, (_T("InitializeSharedAccess failed [%s][%s][0x%x]"),
191 data_->GetFileName(), read_only ? _T("R") : _T("RW"), hr));
192 }
193 }
194
195 // Initialize memory mapped file and sync mechanics.
196 // by calling InitializeSharedAccess
197 SharedMemoryPtr() :
198 file_(INVALID_HANDLE_VALUE), file_mapping_(NULL), data_(NULL) {
199 // This should never happen but let's assert
200 // in case it does.
201 // Each shared data must implement GetSharedData() to use this c-tor.
202 // The implementation should be:
203 // const TCHAR * GetSharedName() const
204 // {return L"Some_unique_string_with_no_spaces";}
205 HRESULT hr = InitializeSharedAccess(data_->GetSharedName(),
206 false,
207 NULL,
208 NULL,
209 false);
210 if (FAILED(hr)) {
211 UTIL_LOG(LE, (_T("InitializeSharedAccess failed [%s][%s][0x%x]"),
212 data_->GetSharedName(), _T("RW"), hr));
213 }
214 }
215
216 // Clean up.
217 ~SharedMemoryPtr() {
218 Cleanup();
219 }
220
221 void Cleanup() {
222 __mutexScope(this);
223 if (data_)
224 UnmapViewOfFile(data_);
225 if (file_mapping_)
226 VERIFY(CloseHandle(file_mapping_), (L""));
227 if (file_ != INVALID_HANDLE_VALUE)
228 VERIFY(CloseHandle(file_), (L""));
229 }
230
231 // Initialize memory mapped file and sync object.
232 bool InitializeSharedAccess(const CString& name,
233 bool persist,
234 LPSECURITY_ATTRIBUTES sa,
235 LPSECURITY_ATTRIBUTES sa_mutex,
236 bool read_only) {
237 return InitializeSharedAccessInternal(name,
238 persist,
239 sa,
240 sa_mutex,
241 read_only,
242 sizeof(T),
243 &T::InitializeSharedData);
244 }
245
246 private:
247 // Initialize memory mapped file and sync object.
248 //
249 // This internal method allows template method folding by only using things
250 // that are consistent in all templates. Things that vary are passed in.
251 bool InitializeSharedAccessInternal(const CString& name, bool persist,
252 LPSECURITY_ATTRIBUTES sa,
253 LPSECURITY_ATTRIBUTES sa_mutex,
254 bool read_only,
255 size_t data_size,
256 void (T::*initialize_shared_data)
257 (const CString&)) {
258 // If this memory mapped object is backed by a file, then "name" is a fully
259 // qualified name with backslashes. Since we can't use backslashes in a
260 // mutex's name, let's make another name where we convert them to
261 // underscores.
262 CString mem_name(name);
263 if (persist) {
264 mem_name.Replace(_T('\\'), _T('_'));
265 }
266
267 // Initialize the mutex
268 CString mutex_name(mem_name + _T("MUTEX"));
269 LPSECURITY_ATTRIBUTES mutex_attr = sa_mutex ? sa_mutex : sa;
270 if (!InitializeWithSecAttr(mutex_name, mutex_attr)) {
271 ASSERT(false, (L"Failed to initialize mutex. Err=%i", ::GetLastError()));
272 return false;
273 }
274
275 // everything is synchronized till the end of the function or return.
276 __mutexScope(this);
277
278 first_instance_ = false;
279
280 if (persist) {
281 // Back this shared memory by a file
282 file_ = CreateFile(name,
283 GENERIC_READ | (read_only ? 0 : GENERIC_WRITE),
284 FILE_SHARE_READ | (read_only ? 0 : FILE_SHARE_WRITE),
285 sa,
286 OPEN_ALWAYS,
287 NULL,
288 NULL);
289 if (file_ == INVALID_HANDLE_VALUE)
290 return false;
291
292 if (!read_only && GetLastError() != ERROR_ALREADY_EXISTS)
293 first_instance_ = true;
294 } else {
295 ASSERT(file_ == INVALID_HANDLE_VALUE, (L""));
296 file_ = INVALID_HANDLE_VALUE;
297 }
298
299 if (read_only) {
300 file_mapping_ = OpenFileMapping(FILE_MAP_READ, false, mem_name);
301 if (!file_mapping_) {
302 UTIL_LOG(LW, (L"[OpenFileMapping failed][error %i]", ::GetLastError()));
303 }
304 } else {
305 file_mapping_ = CreateFileMapping(file_, sa,
306 PAGE_READWRITE, 0, data_size, mem_name);
307 ASSERT(file_mapping_, (L"CreateFileMapping. Err=%i", ::GetLastError()));
308 }
309
310 if (!file_mapping_) {
311 return false;
312 } else if (!read_only &&
313 file_ == INVALID_HANDLE_VALUE &&
314 GetLastError() != ERROR_ALREADY_EXISTS) {
315 first_instance_ = true;
316 }
317
318 data_ = reinterpret_cast<T*>(MapViewOfFile(file_mapping_,
319 FILE_MAP_READ |
320 (read_only ? 0 : FILE_MAP_WRITE),
321 0,
322 0,
323 data_size));
324
325 if (!data_) {
326 ASSERT(false, (L"MapViewOfFile. Err=%i", ::GetLastError()));
327 VERIFY(CloseHandle(file_mapping_), (L""));
328 file_mapping_ = NULL;
329
330 if (file_ != INVALID_HANDLE_VALUE) {
331 VERIFY(CloseHandle(file_), (L""));
332 file_ = INVALID_HANDLE_VALUE;
333 }
334
335 return false;
336 }
337
338 if (!first_instance_) {
339 return true;
340 }
341
342 // If this is the first instance of shared object
343 // call initialization function. This is nice but
344 // at the same time we can not share built in data types.
345 // SharedMemoryPtr<double> - will not compile. But this is OK
346 // We don't want all the overhead to just share couple of bytes.
347 // Signature is void InitializeSharedData()
348 (data_->*initialize_shared_data)(name);
349
350 return true;
351 }
352
353 DISALLOW_EVIL_CONSTRUCTORS(SharedMemoryPtr);
354 };
355
356 // Sometimes we want Singletons that are shared between processes.
357 // SharedMemoryPtr can do that. But if used in C-written module there will be
358 // a need to make SharedMemoryPtr a global object. Making a Singleton from Share dMemoryPtr
359 // is possible in this situation, but syntactically this is very difficult to re ad.
360 // The following template solves the problem. It hides difficult to read details inside.
361 // Usage is the same as SharedMemoryPtr (ONLY through -> operator). Completely t hread-safe.
362 // Can be used in two ways:
363 // Class A {
364 // public:
365 // void foo(){}
366 //
367 //};
368 // SharedMemorySingleton<A> a, b;
369 // a->foo();
370 // b->foo(); //refers to the same data in any process.
371 //
372 // or
373 //
374 // class A : public SharedMemorySingleton<A> {
375 // public:
376 // void foo(){}
377 //};
378 // A a, b;
379 // a->foo();
380 // b->foo(); //refers to the same data in any process.
381
382 template <typename LockType, typename T> class SharedMemorySingleton {
383 public:
384 SharedDataLockingProxy<LockType, T> operator->() {
385 return
386 Singleton<SharedMemoryPtr<LockType, T> >::Instance()->operator->();
387 }
388 };
389
390 } // namespace omaha
391
392 #endif // OMAHA_COMMON_SHARED_MEMORY_PTR_H__
OLDNEW
« no previous file with comments | « base/shared_any.h ('k') | base/shell.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698