1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*++
6
7
8
9Module Name:
10
11 shmobject.hpp
12
13Abstract:
14 Shared memory based object
15
16
17
18--*/
19
20#include "shmobject.hpp"
21#include "pal/malloc.hpp"
22#include "pal/cs.hpp"
23#include "pal/dbgmsg.h"
24
25#include <stddef.h>
26
27SET_DEFAULT_DEBUG_CHANNEL(PAL);
28
29using namespace CorUnix;
30
31/*++
32Function:
33 CSharedMemoryObject::Initialize
34
35 Performs possibly-failing initialization for a newly-constructed
36 object
37
38Parameters:
39 pthr -- thread data for calling thread
40 poa -- the object attributes (e.g., name) for the object
41--*/
42
43PAL_ERROR
44CSharedMemoryObject::Initialize(
45 CPalThread *pthr,
46 CObjectAttributes *poa
47 )
48{
49 PAL_ERROR palError = NO_ERROR;
50 SHMObjData *psmod = NULL;
51
52 _ASSERTE(NULL != pthr);
53 _ASSERTE(NULL != poa);
54
55 ENTRY("CSharedMemoryObject::Initialize"
56 "(this = %p, pthr = %p, poa = %p)\n",
57 this,
58 pthr,
59 poa
60 );
61
62 palError = CPalObjectBase::Initialize(pthr, poa);
63 if (NO_ERROR != palError)
64 {
65 goto InitializeExit;
66 }
67
68 //
69 // If this is a named object it needs to go into the shared domain;
70 // otherwise it remains local
71 //
72
73 if (0 != m_oa.sObjectName.GetStringLength())
74 {
75 m_ObjectDomain = SharedObject;
76
77 palError = AllocateSharedDataItems(&m_shmod, &psmod);
78 if (NO_ERROR != palError || NULL == psmod)
79 {
80 goto InitializeExit;
81 }
82 }
83
84 if (0 != m_pot->GetSharedDataSize())
85 {
86 if (SharedObject == m_ObjectDomain)
87 {
88 //
89 // Map the shared data into our address space
90 //
91 if (NULL == psmod)
92 {
93 ASSERT("psmod should not be NULL");
94 palError = ERROR_INTERNAL_ERROR;
95 goto InitializeExit;
96 }
97
98 m_pvSharedData = SHMPTR_TO_TYPED_PTR(VOID, psmod->shmObjSharedData);
99 if (NULL == m_pvSharedData)
100 {
101 ASSERT("Unable to map shared data area\n");
102 palError = ERROR_INTERNAL_ERROR;
103 goto InitializeExit;
104 }
105 }
106 else
107 {
108 //
109 // Initialize the local shared data lock.
110 //
111
112 palError = m_sdlSharedData.Initialize();
113 if (NO_ERROR != palError)
114 {
115 ERROR("Failure initializing m_sdlSharedData\n");
116 goto InitializeExit;
117 }
118
119 //
120 // Allocate local memory to hold the shared data
121 //
122
123 m_pvSharedData = InternalMalloc(m_pot->GetSharedDataSize());
124 if (NULL == m_pvSharedData)
125 {
126 ERROR("Failure allocating m_pvSharedData (local copy)\n");
127 palError = ERROR_OUTOFMEMORY;
128 goto InitializeExit;
129 }
130 }
131
132 ZeroMemory(m_pvSharedData, m_pot->GetSharedDataSize());
133 }
134
135
136InitializeExit:
137
138 LOGEXIT("CSharedMemoryObject::Initalize returns %d\n", palError);
139
140 return palError;
141}
142
143/*++
144Function:
145 CSharedMemoryObject::InitializeFromExistingSharedData
146
147 Performs possibly-failing initialization for a newly-constructed
148 object that is to represent an existing object (i.e., importing
149 a shared object into this process)
150
151 The shared memory lock must be held when calling this method
152
153Parameters:
154 pthr -- thread data for calling thread
155 poa -- the object attributes for the object
156--*/
157
158PAL_ERROR
159CSharedMemoryObject::InitializeFromExistingSharedData(
160 CPalThread *pthr,
161 CObjectAttributes *poa
162 )
163{
164 PAL_ERROR palError = NO_ERROR;
165 SHMObjData *psmod = NULL;
166
167 _ASSERTE(NULL != pthr);
168 _ASSERTE(NULL != poa);
169
170 ENTRY("CSharedMemoryObject::InitializeFromExistingSharedData"
171 "(this = %p, pthr = %p, poa = %p)\n",
172 this,
173 pthr,
174 poa
175 );
176
177 //
178 // This object is obviously shared...
179 //
180
181 m_ObjectDomain = SharedObject;
182
183 _ASSERTE(NULL != m_shmod);
184
185 psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, m_shmod);
186 if (NULL == psmod)
187 {
188 ASSERT("Unable to map shared object data\n");
189 palError = ERROR_INTERNAL_ERROR;
190 goto InitializeFromExistingSharedDataExit;
191 }
192
193 //
194 // When we're being called on the duplicate handle path the passed
195 // in object attributes likely won't have an object name in it.
196 // If there is an object name in the shared data place that in the
197 // object attributs so that the constructed object has a local copy
198 // of the name
199 //
200
201 if (0 == poa->sObjectName.GetStringLength()
202 && 0 != psmod->dwNameLength)
203 {
204 WCHAR *wsz;
205
206 wsz = SHMPTR_TO_TYPED_PTR(WCHAR, psmod->shmObjName);
207 if (NULL != wsz)
208 {
209 poa->sObjectName.SetStringWithLength(wsz, psmod->dwNameLength);
210 }
211 else
212 {
213 ASSERT("Unable to map object name\n");
214 palError = ERROR_INTERNAL_ERROR;
215 goto InitializeFromExistingSharedDataExit;
216 }
217 }
218#if _DEBUG
219 else if (0 != psmod->dwNameLength)
220 {
221 WCHAR *wsz;
222
223 //
224 // Verify that the names are consistent
225 //
226
227 wsz = SHMPTR_TO_TYPED_PTR(WCHAR, psmod->shmObjName);
228 _ASSERTE(NULL != wsz);
229 _ASSERTE(0 == PAL_wcscmp(wsz, poa->sObjectName.GetString()));
230 }
231#endif // debug
232
233 palError = CPalObjectBase::Initialize(pthr, poa);
234 if (NO_ERROR != palError)
235 {
236 goto InitializeFromExistingSharedDataExit;
237 }
238
239 if (NULL != psmod->shmObjImmutableData)
240 {
241 VOID *pv = SHMPTR_TO_TYPED_PTR(VOID, psmod->shmObjImmutableData);
242 if (NULL != pv)
243 {
244 memcpy(m_pvImmutableData, pv, m_pot->GetImmutableDataSize());
245 if (NULL != psmod->pCopyRoutine)
246 {
247 (*psmod->pCopyRoutine)(pv, m_pvImmutableData);
248 }
249
250 m_pot->SetImmutableDataCopyRoutine(psmod->pCopyRoutine);
251 m_pot->SetImmutableDataCleanupRoutine(psmod->pCleanupRoutine);
252 }
253 else
254 {
255 ASSERT("Unable to map object immutable data\n");
256 palError = ERROR_INTERNAL_ERROR;
257 goto InitializeFromExistingSharedDataExit;
258 }
259 }
260
261 if (NULL != psmod->shmObjSharedData)
262 {
263 m_pvSharedData = SHMPTR_TO_TYPED_PTR(VOID, psmod->shmObjSharedData);
264 if (NULL == m_pvSharedData)
265 {
266 ASSERT("Unable to map object shared data\n");
267 palError = ERROR_INTERNAL_ERROR;
268 goto InitializeFromExistingSharedDataExit;
269 }
270 }
271
272 if (NULL != m_pot->GetObjectInitRoutine())
273 {
274 palError = (*m_pot->GetObjectInitRoutine())(
275 pthr,
276 m_pot,
277 m_pvImmutableData,
278 m_pvSharedData,
279 m_pvLocalData
280 );
281 }
282
283InitializeFromExistingSharedDataExit:
284
285 LOGEXIT("CSharedMemoryObject::InitalizeFromExistingSharedData returns %d\n", palError);
286
287 return palError;
288}
289
290/*++
291Function:
292 CSharedMemoryObject::AllocatedSharedDataItems
293
294 Allocates and initialiazes the shared memory structures necessary to make an
295 object available to other processes
296
297Parameters:
298 pshmObjData -- on success, receives the shared memory pointer for the
299 shared memory object data
300 ppsmod -- on success, receives the locally-mapped pointer for the shared
301 memory object data
302--*/
303
304PAL_ERROR
305CSharedMemoryObject::AllocateSharedDataItems(
306 SHMPTR *pshmObjData,
307 SHMObjData **ppsmod
308 )
309{
310 PAL_ERROR palError = NO_ERROR;
311 SHMPTR shmod = NULL;
312 SHMObjData *psmod = NULL;
313
314 _ASSERTE(NULL != pshmObjData);
315 _ASSERTE(NULL != ppsmod);
316
317 ENTRY("CSharedMemoryObject::AllocateSharedDataItems"
318 "(this = %p, pshmObjData = %p, ppsmod = %p)\n",
319 this,
320 pshmObjData,
321 ppsmod
322 );
323
324 //
325 // We're about to make a number of shared memory allocations,
326 // so grab the lock for the entirety of the routine.
327 //
328
329 SHMLock();
330
331 shmod = malloc(sizeof(SHMObjData));
332 if (NULL == shmod)
333 {
334 ERROR("Unable to allocate m_shmod for new object\n");
335 palError = ERROR_OUTOFMEMORY;
336 goto AllocateSharedDataItemsExit;
337 }
338
339 psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, shmod);
340 _ASSERTE(NULL != psmod);
341
342 ZeroMemory(psmod, sizeof(*psmod));
343
344 psmod->eTypeId = m_pot->GetId();
345 psmod->lProcessRefCount = 1;
346
347 if (0 != m_oa.sObjectName.GetStringLength())
348 {
349 LPCWSTR str = m_oa.sObjectName.GetString();
350 _ASSERTE(str);
351
352 psmod->dwNameLength = m_oa.sObjectName.GetStringLength();
353
354 UINT length = (PAL_wcslen(str) + 1) * sizeof(WCHAR);
355 psmod->shmObjName = malloc(length);
356
357 if (psmod->shmObjName != 0)
358 {
359 memcpy(psmod->shmObjName, str, length);
360 }
361 else
362 {
363 ERROR("Unable to allocate psmod->shmObjName for new object\n");
364 palError = ERROR_OUTOFMEMORY;
365 goto AllocateSharedDataItemsExit;
366 }
367 }
368
369 if (0 != m_pot->GetImmutableDataSize())
370 {
371 //
372 // The shared copy of the object's immutable data will be initialized
373 // by CSharedMemoryObjectManager::RegisterObject or PromoteSharedData
374 //
375
376 psmod->shmObjImmutableData = malloc(m_pot->GetImmutableDataSize());
377 if (NULL == psmod->shmObjImmutableData)
378 {
379 ERROR("Unable to allocate psmod->shmObjImmutableData for new object\n");
380 palError = ERROR_OUTOFMEMORY;
381 goto AllocateSharedDataItemsExit;
382 }
383 }
384
385 if (0 != m_pot->GetSharedDataSize())
386 {
387 psmod->shmObjSharedData = malloc(m_pot->GetSharedDataSize());
388 if (NULL == psmod->shmObjSharedData)
389 {
390 ERROR("Unable to allocate psmod->shmObjSharedData for new object\n");
391 palError = ERROR_OUTOFMEMORY;
392 goto AllocateSharedDataItemsExit;
393 }
394 }
395
396 *pshmObjData = shmod;
397 *ppsmod = psmod;
398
399AllocateSharedDataItemsExit:
400
401 if (NO_ERROR != palError && NULL != shmod)
402 {
403 FreeSharedDataAreas(shmod);
404 }
405
406 SHMRelease();
407
408 LOGEXIT("CSharedMemoryObject::AllocateSharedDataItems returns %d\n", palError);
409
410 return palError;
411}
412
413/*++
414Function:
415 CSharedMemoryObject::FreeSharedDataItems
416
417 Frees the shared memory structures referenced by the provided shared
418 memory pointer
419
420Parameters:
421 shmObjData -- shared memory pointer to the structures to free
422--*/
423
424// static
425void
426CSharedMemoryObject::FreeSharedDataAreas(
427 SHMPTR shmObjData
428 )
429{
430 SHMObjData *psmod;
431
432 _ASSERTE(NULL != shmObjData);
433
434 ENTRY("CSharedMemoryObject::FreeSharedDataAreas"
435 "(shmObjData = %p)\n",
436 shmObjData
437 );
438
439 SHMLock();
440
441 psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, shmObjData);
442 _ASSERTE(NULL != psmod);
443
444 if (NULL != psmod->shmObjImmutableData)
445 {
446 if (NULL != psmod->pCleanupRoutine)
447 {
448 (*psmod->pCleanupRoutine)(psmod->shmObjImmutableData);
449 }
450 free(psmod->shmObjImmutableData);
451 }
452
453 if (NULL != psmod->shmObjSharedData)
454 {
455 free(psmod->shmObjSharedData);
456 }
457
458 if (NULL != psmod->shmObjName)
459 {
460 free(psmod->shmObjName);
461 }
462
463 free(shmObjData);
464
465 SHMRelease();
466
467 LOGEXIT("CSharedMemoryObject::FreeSharedDataAreas\n");
468}
469
470/*++
471Function:
472 CSharedMemoryObject::CleanupForProcessShutdown
473
474 Cleanup routine called by the object manager when shutting down
475
476Parameters:
477 pthr -- thread data for the calling thread
478--*/
479
480void
481CSharedMemoryObject::CleanupForProcessShutdown(
482 CPalThread *pthr
483 )
484{
485 bool fCleanupSharedState;
486
487 _ASSERTE(NULL != pthr);
488
489 ENTRY("CSharedMemoryObject::CleanupForProcessShutdown"
490 "(this = %p, pthr = %p)\n",
491 this,
492 pthr
493 );
494
495 fCleanupSharedState = DereferenceSharedData();
496
497 if (NULL != m_pot->GetObjectCleanupRoutine())
498 {
499 (*m_pot->GetObjectCleanupRoutine())(
500 pthr,
501 static_cast<IPalObject*>(this),
502 TRUE,
503 fCleanupSharedState
504 );
505 }
506
507 if (NULL != m_pot->GetImmutableDataCleanupRoutine())
508 {
509 (*m_pot->GetImmutableDataCleanupRoutine())(m_pvImmutableData);
510 }
511
512 if (NULL != m_pot->GetProcessLocalDataCleanupRoutine())
513 {
514 (*m_pot->GetProcessLocalDataCleanupRoutine())(pthr, static_cast<IPalObject*>(this));
515 }
516
517 //
518 // We need to do two things with the calling thread data here:
519 // 1) store it in m_pthrCleanup so it is available to the destructors
520 // 2) Add a reference to it before starting any cleanup, and release
521 // that reference afterwords.
522 //
523 // Step 2 is necessary when we're cleaning up the thread object that
524 // represents the calling thread -- it ensures that the thread data
525 // is available throughout the entire cleanup process.
526 //
527
528 m_pthrCleanup = pthr;
529 pthr->AddThreadReference();
530
531 InternalDelete(this);
532
533 pthr->ReleaseThreadReference();
534
535 LOGEXIT("CSharedMemoryObject::CleanupForProcessShutdown\n");
536}
537
538/*++
539Function:
540 CSharedMemoryObject::AcquiteObjectDestructionLock
541
542 Acquires the lock that must be held when decrementing the object's
543 reference count (and, if the count drops to 0, while removing the
544 object from the object manager's lists).
545
546Parameters:
547 pthr -- thread data for the calling thread
548--*/
549
550void
551CSharedMemoryObject::AcquireObjectDestructionLock(
552 CPalThread *pthr
553 )
554{
555 _ASSERTE(NULL != pthr);
556
557 ENTRY("CSharedMemoryObject::AcquireObjectDestructionLock"
558 "(this = %p, pthr = $p)\n",
559 this,
560 pthr
561 );
562
563 InternalEnterCriticalSection(pthr, m_pcsObjListLock);
564
565 LOGEXIT("CSharedMemoryObject::AcquireObjectDestructionLock\n");
566}
567
568/*++
569Function:
570 CSharedMemoryObject::ReleaseObjectDestructionLock
571
572 Releases the lock acquired by AcquireObjectDestructionLock
573
574Parameters:
575 pthr -- thread data for the calling thread
576 fDestructionPending -- if TRUE, the reference count for this
577 object has dropped to 0; the object will be destroyed after
578 this routine returns
579--*/
580
581bool
582CSharedMemoryObject::ReleaseObjectDestructionLock(
583 CPalThread *pthr,
584 bool fDestructionPending
585 )
586{
587 bool fCleanupSharedState = FALSE;
588
589 _ASSERTE(NULL != pthr);
590
591 ENTRY("CSharedMemoryObject::ReleaseObjectDestructionLock"
592 "(this = %p, pthr = %p, fDestructionPending = %d\n",
593 this,
594 pthr,
595 fDestructionPending
596 );
597
598 if (fDestructionPending)
599 {
600 RemoveEntryList(&m_le);
601 fCleanupSharedState = DereferenceSharedData();
602 }
603
604 InternalLeaveCriticalSection(pthr, m_pcsObjListLock);
605
606 LOGEXIT("CSharedMemoryObject::ReleaseObjectDestructionLock returns %d\n",
607 fCleanupSharedState
608 );
609
610 return fCleanupSharedState;
611}
612
613/*++
614Function:
615 CSharedMemoryObject::DereferenceSharedData
616
617 Called to decrement the global refcount (i.e., the count of
618 the number of processes that have reference to the object) when
619 the local reference to the object is being destroyed.
620
621Return value:
622 Returns TRUE if this process needs to clean up the object's shared
623 data (i.e., the global refcount has dropped to 0, or the object
624 is in the local domain)
625--*/
626
627bool
628CSharedMemoryObject::DereferenceSharedData()
629{
630 LONG fSharedDataAlreadDereferenced;
631
632 ENTRY("CSharedMemoryObject::DereferenceSharedData(this = %p)\n", this);
633
634 fSharedDataAlreadDereferenced = InterlockedExchange(
635 &m_fSharedDataDereferenced,
636 TRUE
637 );
638
639 if (!fSharedDataAlreadDereferenced)
640 {
641 if (NULL != m_shmod)
642 {
643 SHMObjData *psmod;
644
645 SHMLock();
646
647 psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, m_shmod);
648 _ASSERTE(NULL != psmod);
649
650 psmod->lProcessRefCount -= 1;
651 if (0 == psmod->lProcessRefCount)
652 {
653 //
654 // No other process is using this object, so remove
655 // it from the shared memory named object list (if it
656 // had been added to it). The final cleanup will happen
657 // in the object's destructor
658 //
659
660 m_fDeleteSharedData = TRUE;
661
662 if (psmod->fAddedToList)
663 {
664 //
665 // This object better have a name...
666 //
667
668 _ASSERTE(0 != psmod->dwNameLength);
669
670 if (NULL != psmod->shmPrevObj)
671 {
672 SHMObjData *psmodPrevious = SHMPTR_TO_TYPED_PTR(SHMObjData, psmod->shmPrevObj);
673 _ASSERTE(NULL != psmodPrevious);
674
675 psmodPrevious->shmNextObj = psmod->shmNextObj;
676 }
677 else
678 {
679 //
680 // This object is the head of the shared memory named object
681 // list -- reset that pointer now
682 //
683
684 if (!SHMSetInfo(SIID_NAMED_OBJECTS, psmod->shmNextObj))
685 {
686 ASSERT("Failed to set shared named object list head");
687 }
688 }
689
690 if (NULL != psmod->shmNextObj)
691 {
692 SHMObjData *psmodNext = SHMPTR_TO_TYPED_PTR(SHMObjData, psmod->shmNextObj);
693 _ASSERTE(NULL != psmodNext);
694
695 psmodNext->shmPrevObj = psmod->shmPrevObj;
696 }
697 }
698#if _DEBUG
699 else
700 {
701 _ASSERTE(NULL == psmod->shmPrevObj);
702 _ASSERTE(NULL == psmod->shmNextObj);
703 }
704#endif
705 }
706
707 SHMRelease();
708 }
709 else if (ProcessLocalObject == m_ObjectDomain)
710 {
711 //
712 // If the object is local the shared data needs to be
713 // deleted by definition
714 //
715
716 m_fDeleteSharedData = TRUE;
717 }
718 }
719 else
720 {
721 ASSERT("Multiple calls to DereferenceSharedData\n");
722 }
723
724 LOGEXIT("CSharedMemoryObject::DereferenceSharedData returns %d\n",
725 m_fDeleteSharedData
726 );
727
728 return m_fDeleteSharedData;
729}
730
731/*++
732Function:
733 CSharedMemoryObject::~CSharedMemoryObject
734
735 Destructor; should only be called from ReleaseReference
736--*/
737
738CSharedMemoryObject::~CSharedMemoryObject()
739{
740 ENTRY("CSharedMemoryObject::~CSharedMemoryObject(this = %p)\n", this);
741
742 if (!m_fSharedDataDereferenced)
743 {
744 ASSERT("DereferenceSharedData not called before object destructor -- delete called directly?\n");
745 DereferenceSharedData();
746 }
747
748 if (NULL != m_pvSharedData && ProcessLocalObject == m_ObjectDomain)
749 {
750 free(m_pvSharedData);
751 }
752 else if (NULL != m_shmod && m_fDeleteSharedData)
753 {
754 FreeSharedDataAreas(m_shmod);
755 }
756
757 LOGEXIT("CSharedMemoryObject::~CSharedMemoryObject\n");
758}
759
760//
761// C++ standard, 18.1.5 - offsetof requires a POD (plain old data) struct or
762// union. Since offsetof is a macro, gcc doesn't actually check for improper
763// use of offsetof, it keys off of the -> from NULL (which is also invalid for
764// non-POD types by 18.1.5)
765//
766// As we have numerous examples of this behavior in our codebase,
767// making an offsetof which doesn't use 0.
768//
769// PAL_safe_offsetof is a version of offsetof that protects against an
770// overridden operator&
771//
772
773#define PAL_safe_offsetof(s,m) ((size_t)((ptrdiff_t)&(char&)(((s *)64)->m))-64)
774
775/*++
776Function:
777 CSharedMemoryObject::GetObjectFromListLink
778
779 Given a list link returns the object that contains it. Since m_le is
780 protected the caller cannot perform this computation directly
781
782Parameters:
783 ple -- the list entry to obtain the object for
784--*/
785
786// static
787CSharedMemoryObject*
788CSharedMemoryObject::GetObjectFromListLink(PLIST_ENTRY ple)
789{
790 CSharedMemoryObject *pshmo;
791
792 _ASSERTE(NULL != ple);
793
794 ENTRY("CSharedMemoryObject::GetObjectFromListLink(ple = %p)\n", ple);
795
796 //
797 // Ideally we'd use CONTAINING_RECORD here, but it uses offsetof (see above
798 // comment
799 //
800
801 pshmo = reinterpret_cast<CSharedMemoryObject*>(
802 reinterpret_cast<size_t>(ple) - PAL_safe_offsetof(CSharedMemoryObject, m_le)
803 );
804
805 _ASSERTE(ple == &pshmo->m_le);
806
807 LOGEXIT("CSharedMemoryObject::GetObjectFromListLink returns %p\n", pshmo);
808
809 return pshmo;
810}
811
812/*++
813Function:
814 CSharedMemoryObject::GetSharedData
815
816 Provides the caller access to the object's shared data (if any)
817
818Parameters:
819 pthr -- thread data for calling thread
820 eLockRequest -- specifies if the caller desires a read lock or a
821 write lock on the data (currently ignored)
822 ppDataLock -- on success, receives a pointer to the data lock instance
823 for the shared data
824 ppvProcssSharedData -- on success, receives a pointer to the shared data
825--*/
826
827PAL_ERROR
828CSharedMemoryObject::GetSharedData(
829 CPalThread *pthr,
830 LockType eLockRequest,
831 IDataLock **ppDataLock, // OUT
832 void **ppvSharedData // OUT
833 )
834{
835 IDataLock *pDataLock;
836
837 _ASSERTE(NULL != pthr);
838 _ASSERTE(ReadLock == eLockRequest || WriteLock == eLockRequest);
839 _ASSERTE(NULL != ppDataLock);
840 _ASSERTE(NULL != ppvSharedData);
841
842 ENTRY("CSharedMemoryObject::GetSharedData"
843 "(this = %p, pthr = %p, eLockRequest = %d, ppDataLock = %p,"
844 " ppvSharedData = %p)\n",
845 this,
846 pthr,
847 eLockRequest,
848 ppDataLock,
849 ppvSharedData
850 );
851
852 _ASSERTE(0 < m_pot->GetSharedDataSize());
853
854 if (ProcessLocalObject == m_ObjectDomain)
855 {
856 //
857 // We need to grab the local shared data lock and re-check
858 // the object's domain, as there's a chance the object might
859 // have been promoted after we made the above check but before
860 // we grabbed the lock
861 //
862
863 m_sdlSharedData.AcquireLock(pthr, &pDataLock);
864
865 if (SharedObject == m_ObjectDomain)
866 {
867 pDataLock->ReleaseLock(pthr, FALSE);
868 m_ssmlSharedData.AcquireLock(pthr, &pDataLock);
869 }
870 }
871 else
872 {
873 //
874 // A shared object can never transition back to local,
875 // so there's no need to recheck the domain on this path
876 //
877
878 m_ssmlSharedData.AcquireLock(pthr, &pDataLock);
879 }
880
881 *ppDataLock = pDataLock;
882 *ppvSharedData = m_pvSharedData;
883
884 LOGEXIT("CSharedMemoryObject::GetSharedData returns %d\n", NO_ERROR);
885
886 return NO_ERROR;
887}
888
889/*++
890Function:
891 CSharedMemoryObject::GetSynchStateController
892
893 Obtain a synchronization state controller for this object. Should
894 never be called.
895
896Parameters:
897 pthr -- thread data for calling thread
898 ppStateController -- on success, receives a pointer to the state controller
899 instance
900--*/
901
902PAL_ERROR
903CSharedMemoryObject::GetSynchStateController(
904 CPalThread *pthr,
905 ISynchStateController **ppStateController // OUT
906 )
907{
908 _ASSERTE(NULL != pthr);
909 _ASSERTE(NULL != ppStateController);
910
911 //
912 // This is not a waitable object!
913 //
914
915 ASSERT("Attempt to obtain a synch state controller on a non-waitable object\n");
916 return ERROR_INVALID_HANDLE;
917}
918
919/*++
920Function:
921 CSharedMemoryObject::GetSynchWaitController
922
923 Obtain a synchronization wait controller for this object. Should
924 never be called.
925
926Parameters:
927 pthr -- thread data for calling thread
928 ppWaitController -- on success, receives a pointer to the wait controller
929 instance
930--*/
931
932PAL_ERROR
933CSharedMemoryObject::GetSynchWaitController(
934 CPalThread *pthr,
935 ISynchWaitController **ppWaitController // OUT
936 )
937{
938 _ASSERTE(NULL != pthr);
939 _ASSERTE(NULL != ppWaitController);
940
941 //
942 // This is not a waitable object!!!
943 //
944
945 ASSERT("Attempt to obtain a synch wait controller on a non-waitable object\n");
946 return ERROR_INVALID_HANDLE;
947}
948
949/*++
950Function:
951 CSharedMemoryObject::GetObjectDomain
952
953 Returns the object's domain (local or shared)
954
955--*/
956
957ObjectDomain
958CSharedMemoryObject::GetObjectDomain(
959 void
960 )
961{
962 TRACE("CSharedMemoryObject::GetObjectDomain(this = %p)\n", this);
963 LOGEXIT("CSharedMemoryObject::GetObjectDomain returns %d\n", m_ObjectDomain);
964
965 return m_ObjectDomain;
966}
967
968/*++
969Function:
970 CSharedMemoryObject::GetObjectSynchData
971
972 Obtain the synchronization data for this object. Should
973 never be called.
974
975Parameters:
976 ppvSynchData -- on success, receives a pointer to the object's synch data
977--*/
978
979PAL_ERROR
980CSharedMemoryObject::GetObjectSynchData(
981 VOID **ppvSynchData // OUT
982 )
983{
984 _ASSERTE(NULL != ppvSynchData);
985
986 //
987 // This is not a waitable object!!!
988 //
989
990 ASSERT("Attempt to obtain a synch data for a non-waitable object\n");
991 return ERROR_INVALID_HANDLE;
992}
993
994/*++
995Function:
996 CSharedMemoryWaitableObject::Initialize
997
998 Performs possibly-failing initialization for a newly-constructed
999 object
1000
1001Parameters:
1002 pthr -- thread data for calling thread
1003 poa -- the object attributes (e.g., name) for the object
1004--*/
1005
1006PAL_ERROR
1007CSharedMemoryWaitableObject::Initialize(
1008 CPalThread *pthr,
1009 CObjectAttributes *poa
1010 )
1011{
1012 PAL_ERROR palError = NO_ERROR;
1013
1014 _ASSERTE(NULL != pthr);
1015 _ASSERTE(NULL != poa);
1016
1017 ENTRY("CSharedMemoryWaitableObject::Initialize"
1018 "(this = %p, pthr = %p, poa = %p)\n",
1019 this,
1020 pthr,
1021 poa
1022 );
1023
1024 palError = CSharedMemoryObject::Initialize(pthr, poa);
1025 if (NO_ERROR != palError)
1026 {
1027 goto InitializeExit;
1028 }
1029
1030 //
1031 // Sanity check the passed in object type
1032 //
1033
1034 _ASSERTE(CObjectType::WaitableObject == m_pot->GetSynchronizationSupport());
1035
1036 palError = g_pSynchronizationManager->AllocateObjectSynchData(
1037 m_pot,
1038 m_ObjectDomain,
1039 &m_pvSynchData
1040 );
1041
1042 if (NO_ERROR == palError && SharedObject == m_ObjectDomain)
1043 {
1044 SHMObjData *pshmod = SHMPTR_TO_TYPED_PTR(SHMObjData, m_shmod);
1045 _ASSERTE(NULL != pshmod);
1046
1047 pshmod->pvSynchData = m_pvSynchData;
1048 }
1049
1050InitializeExit:
1051
1052 LOGEXIT("CSharedMemoryWaitableObject::Initialize returns %d\n", palError);
1053
1054 return palError;
1055}
1056
1057/*++
1058Function:
1059 CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject
1060
1061 Destructor; should only be called from ReleaseReference
1062--*/
1063
1064CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject()
1065{
1066 ENTRY("CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject"
1067 "(this = %p)\n",
1068 this
1069 );
1070
1071 if (!m_fSharedDataDereferenced)
1072 {
1073 ASSERT("DereferenceSharedData not called before object destructor -- delete called directly?\n");
1074 DereferenceSharedData();
1075 }
1076
1077 if (NULL != m_pvSynchData && m_fDeleteSharedData)
1078 {
1079 g_pSynchronizationManager->FreeObjectSynchData(
1080 m_pot,
1081 m_ObjectDomain,
1082 m_pvSynchData
1083 );
1084 }
1085
1086 LOGEXIT("CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject\n");
1087}
1088
1089/*++
1090Function:
1091 CSharedMemoryWaitableObject::GetSynchStateController
1092
1093 Obtain a synchronization state controller for this object.
1094
1095Parameters:
1096 pthr -- thread data for calling thread
1097 ppStateController -- on success, receives a pointer to the state controller
1098 instance
1099--*/
1100
1101PAL_ERROR
1102CSharedMemoryWaitableObject::GetSynchStateController(
1103 CPalThread *pthr, // IN, OPTIONAL
1104 ISynchStateController **ppStateController // OUT
1105 )
1106{
1107 PAL_ERROR palError = NO_ERROR;
1108
1109 _ASSERTE(NULL != pthr);
1110 _ASSERTE(NULL != ppStateController);
1111
1112 ENTRY("CSharedMemoryWaitableObject::GetSynchStateController"
1113 "(this = %p, pthr = %p, ppStateController = %p",
1114 this,
1115 pthr,
1116 ppStateController
1117 );
1118
1119 //
1120 // We need to grab the local synch lock before creating the controller
1121 // (otherwise we could get promoted after passing in our parameters)
1122 //
1123
1124 g_pSynchronizationManager->AcquireProcessLock(pthr);
1125
1126 palError = g_pSynchronizationManager->CreateSynchStateController(
1127 pthr,
1128 m_pot,
1129 m_pvSynchData,
1130 m_ObjectDomain,
1131 ppStateController
1132 );
1133
1134 g_pSynchronizationManager->ReleaseProcessLock(pthr);
1135
1136 LOGEXIT("CSharedMemoryWaitableObject::GetSynchStateController returns %d\n",
1137 palError
1138 );
1139
1140 return palError;
1141}
1142
1143/*++
1144Function:
1145 CSharedMemoryWaitableObject::GetSynchWaitController
1146
1147 Obtain a synchronization wait controller for this object.
1148
1149Parameters:
1150 pthr -- thread data for calling thread
1151 ppWaitController -- on success, receives a pointer to the wait controller
1152 instance
1153--*/
1154
1155PAL_ERROR
1156CSharedMemoryWaitableObject::GetSynchWaitController(
1157 CPalThread *pthr, // IN, OPTIONAL
1158 ISynchWaitController **ppWaitController // OUT
1159 )
1160{
1161 PAL_ERROR palError = NO_ERROR;
1162
1163 _ASSERTE(NULL != pthr);
1164 _ASSERTE(NULL != ppWaitController);
1165
1166 ENTRY("CSharedMemoryWaitableObject::GetSynchWaitController"
1167 "(this = %p, pthr = %p, ppWaitController = %p",
1168 this,
1169 pthr,
1170 ppWaitController
1171 );
1172
1173 //
1174 // We need to grab the local synch lock before creating the controller
1175 // (otherwise we could get promoted after passing in our parameters)
1176 //
1177
1178 g_pSynchronizationManager->AcquireProcessLock(pthr);
1179
1180 palError = g_pSynchronizationManager->CreateSynchWaitController(
1181 pthr,
1182 m_pot,
1183 m_pvSynchData,
1184 m_ObjectDomain,
1185 ppWaitController
1186 );
1187
1188 g_pSynchronizationManager->ReleaseProcessLock(pthr);
1189
1190 LOGEXIT("CSharedMemoryWaitableObject::GetSynchWaitController returns %d\n",
1191 palError
1192 );
1193
1194 return palError;
1195}
1196
1197/*++
1198Function:
1199 CSharedMemoryWaitableObject::GetObjectSynchData
1200
1201 Obtain the synchronization data for this object. This method should only
1202 be called by the synchronization manager
1203
1204Parameters:
1205 ppvSynchData -- on success, receives a pointer to the object's synch data
1206--*/
1207
1208PAL_ERROR
1209CSharedMemoryWaitableObject::GetObjectSynchData(
1210 VOID **ppvSynchData // OUT
1211 )
1212{
1213 _ASSERTE(NULL != ppvSynchData);
1214
1215 ENTRY("CSharedMemoryWaitableObject::GetObjectSynchData"
1216 "(this = %p, ppvSynchData = %p)\n",
1217 this,
1218 ppvSynchData
1219 );
1220
1221 *ppvSynchData = m_pvSynchData;
1222
1223 LOGEXIT("CSharedMemoryWaitableObject::GetObjectSynchData returns %d\n",
1224 NO_ERROR
1225 );
1226
1227 return NO_ERROR;
1228}
1229
1230