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 | |
9 | Module Name: |
10 | |
11 | shmobjectmgr.cpp |
12 | |
13 | Abstract: |
14 | Shared memory based object manager |
15 | |
16 | |
17 | |
18 | --*/ |
19 | |
20 | #include "shmobjectmanager.hpp" |
21 | #include "shmobject.hpp" |
22 | #include "pal/cs.hpp" |
23 | #include "pal/thread.hpp" |
24 | #include "pal/procobj.hpp" |
25 | #include "pal/dbgmsg.h" |
26 | |
27 | SET_DEFAULT_DEBUG_CHANNEL(PAL); |
28 | |
29 | #include "pal/corunix.inl" |
30 | |
31 | using namespace CorUnix; |
32 | |
33 | IPalObjectManager * CorUnix::g_pObjectManager; |
34 | |
35 | static |
36 | PAL_ERROR |
37 | CheckObjectTypeAndRights( |
38 | IPalObject *pobj, |
39 | CAllowedObjectTypes *paot, |
40 | DWORD dwRightsGranted, |
41 | DWORD dwRightsRequired |
42 | ); |
43 | |
44 | /*++ |
45 | Function: |
46 | CSharedMemoryObjectManager::Initialize |
47 | |
48 | Performs (possibly failing) startup tasks for the object manager |
49 | |
50 | Parameters: |
51 | None |
52 | --*/ |
53 | |
54 | PAL_ERROR |
55 | CSharedMemoryObjectManager::Initialize( |
56 | void |
57 | ) |
58 | { |
59 | PAL_ERROR palError = NO_ERROR; |
60 | |
61 | ENTRY("CSharedMemoryObjectManager::Initialize (this=%p)\n" , this); |
62 | |
63 | InitializeListHead(&m_leNamedObjects); |
64 | InitializeListHead(&m_leAnonymousObjects); |
65 | |
66 | InternalInitializeCriticalSection(&m_csListLock); |
67 | m_fListLockInitialized = TRUE; |
68 | |
69 | palError = m_HandleManager.Initialize(); |
70 | |
71 | LOGEXIT("CSharedMemoryObjectManager::Initialize returns %d" , palError); |
72 | |
73 | return palError; |
74 | } |
75 | |
76 | /*++ |
77 | Function: |
78 | CSharedMemoryObjectManager::Shutdown |
79 | |
80 | Cleans up the object manager. This routine will call cleanup routines |
81 | for all objects referenced by this process. After this routine is called |
82 | no attempt should be made to access an IPalObject. |
83 | |
84 | Parameters: |
85 | pthr -- thread data for calling thread |
86 | --*/ |
87 | |
88 | PAL_ERROR |
89 | CSharedMemoryObjectManager::Shutdown( |
90 | CPalThread *pthr |
91 | ) |
92 | { |
93 | PLIST_ENTRY ple; |
94 | CSharedMemoryObject *pshmobj; |
95 | |
96 | _ASSERTE(NULL != pthr); |
97 | |
98 | ENTRY("CSharedMemoryObjectManager::Shutdown (this=%p, pthr=%p)\n" , |
99 | this, |
100 | pthr |
101 | ); |
102 | |
103 | InternalEnterCriticalSection(pthr, &m_csListLock); |
104 | SHMLock(); |
105 | |
106 | while (!IsListEmpty(&m_leAnonymousObjects)) |
107 | { |
108 | ple = RemoveTailList(&m_leAnonymousObjects); |
109 | pshmobj = CSharedMemoryObject::GetObjectFromListLink(ple); |
110 | pshmobj->CleanupForProcessShutdown(pthr); |
111 | } |
112 | |
113 | while (!IsListEmpty(&m_leNamedObjects)) |
114 | { |
115 | ple = RemoveTailList(&m_leNamedObjects); |
116 | pshmobj = CSharedMemoryObject::GetObjectFromListLink(ple); |
117 | pshmobj->CleanupForProcessShutdown(pthr); |
118 | } |
119 | |
120 | SHMRelease(); |
121 | InternalLeaveCriticalSection(pthr, &m_csListLock); |
122 | |
123 | LOGEXIT("CSharedMemoryObjectManager::Shutdown returns %d\n" , NO_ERROR); |
124 | |
125 | return NO_ERROR; |
126 | } |
127 | |
128 | /*++ |
129 | Function: |
130 | CSharedMemoryObjectManager::AllocateObject |
131 | |
132 | Allocates a new object instance of the specified type. |
133 | |
134 | Parameters: |
135 | pthr -- thread data for calling thread |
136 | pot -- type of object to allocate |
137 | poa -- attributes (name and SD) of object to allocate |
138 | ppobjNew -- on success, receives a reference to the new object |
139 | --*/ |
140 | |
141 | PAL_ERROR |
142 | CSharedMemoryObjectManager::AllocateObject( |
143 | CPalThread *pthr, |
144 | CObjectType *pot, |
145 | CObjectAttributes *poa, |
146 | IPalObject **ppobjNew // OUT |
147 | ) |
148 | { |
149 | PAL_ERROR palError = NO_ERROR; |
150 | CSharedMemoryObject *pshmobj = NULL; |
151 | |
152 | _ASSERTE(NULL != pthr); |
153 | _ASSERTE(NULL != pot); |
154 | _ASSERTE(NULL != poa); |
155 | _ASSERTE(NULL != ppobjNew); |
156 | |
157 | ENTRY("CSharedMemoryObjectManager::AllocateObject " |
158 | "(this=%p, pthr=%p, pot=%p, poa=%p, ppobjNew=%p)\n" , |
159 | this, |
160 | pthr, |
161 | pot, |
162 | poa, |
163 | ppobjNew |
164 | ); |
165 | |
166 | if (CObjectType::WaitableObject == pot->GetSynchronizationSupport()) |
167 | { |
168 | pshmobj = InternalNew<CSharedMemoryWaitableObject>(pot, &m_csListLock); |
169 | } |
170 | else |
171 | { |
172 | pshmobj = InternalNew<CSharedMemoryObject>(pot, &m_csListLock); |
173 | } |
174 | |
175 | if (NULL != pshmobj) |
176 | { |
177 | palError = pshmobj->Initialize(pthr, poa); |
178 | if (NO_ERROR == palError) |
179 | { |
180 | *ppobjNew = static_cast<IPalObject*>(pshmobj); |
181 | } |
182 | } |
183 | else |
184 | { |
185 | ERROR("Unable to allocate pshmobj\n" ); |
186 | palError = ERROR_OUTOFMEMORY; |
187 | } |
188 | |
189 | LOGEXIT("CSharedMemoryObjectManager::AllocateObject returns %d\n" , palError); |
190 | return palError; |
191 | } |
192 | |
193 | /*++ |
194 | Function: |
195 | CSharedMemoryObjectManager::RegisterObject |
196 | |
197 | Registers a newly-allocated object instance. If the object to be registered |
198 | has a name, and a previously registered object has the same name the new |
199 | object will not be registered. |
200 | |
201 | Distinguished return values: |
202 | ERROR_ALREADY_EXISTS -- an object of a compatible type was already registered |
203 | with the specified name |
204 | ERROR_INVALID_HANDLE -- an object of an incompatible type was already |
205 | registered with the specified name |
206 | |
207 | Parameters: |
208 | pthr -- thread data for calling thread |
209 | pobjToRegister -- the object instance to register. This routine will always |
210 | call ReleaseReference on this instance |
211 | paot -- object types that are compatible with the new object instance |
212 | dwRightsRequested -- requested access rights for the returned handle (ignored) |
213 | pHandle -- on success, receives a handle to the registered object |
214 | ppobjRegistered -- on success, receives a reference to the registered object |
215 | instance. |
216 | --*/ |
217 | |
218 | PAL_ERROR |
219 | CSharedMemoryObjectManager::RegisterObject( |
220 | CPalThread *pthr, |
221 | IPalObject *pobjToRegister, |
222 | CAllowedObjectTypes *paot, |
223 | DWORD dwRightsRequested, |
224 | HANDLE *pHandle, // OUT |
225 | IPalObject **ppobjRegistered // OUT |
226 | ) |
227 | { |
228 | PAL_ERROR palError = NO_ERROR; |
229 | CSharedMemoryObject *pshmobj = static_cast<CSharedMemoryObject*>(pobjToRegister); |
230 | SHMObjData *psmodNew = NULL; |
231 | CObjectAttributes *poa; |
232 | CObjectType *potObj; |
233 | IPalObject *pobjExisting; |
234 | BOOL fInherit = FALSE; |
235 | BOOL fShared = FALSE; |
236 | |
237 | _ASSERTE(NULL != pthr); |
238 | _ASSERTE(NULL != pobjToRegister); |
239 | _ASSERTE(NULL != paot); |
240 | _ASSERTE(NULL != pHandle); |
241 | _ASSERTE(NULL != ppobjRegistered); |
242 | |
243 | ENTRY("CSharedMemoryObjectManager::RegisterObject " |
244 | "(this=%p, pthr=%p, pobjToRegister=%p, paot=%p, " |
245 | "dwRightsRequested=%d, pHandle=%p, ppobjRegistered=%p)\n" , |
246 | this, |
247 | pthr, |
248 | pobjToRegister, |
249 | paot, |
250 | dwRightsRequested, |
251 | pHandle, |
252 | ppobjRegistered |
253 | ); |
254 | |
255 | poa = pobjToRegister->GetObjectAttributes(); |
256 | _ASSERTE(NULL != poa); |
257 | |
258 | if (NULL != poa->pSecurityAttributes) |
259 | { |
260 | fInherit = poa->pSecurityAttributes->bInheritHandle; |
261 | } |
262 | |
263 | potObj = pobjToRegister->GetObjectType(); |
264 | fShared = (SharedObject == pshmobj->GetObjectDomain()); |
265 | |
266 | InternalEnterCriticalSection(pthr, &m_csListLock); |
267 | |
268 | if (fShared) |
269 | { |
270 | // |
271 | // We only need to acquire the shared memory lock if this |
272 | // object is actually shared. |
273 | // |
274 | |
275 | SHMLock(); |
276 | } |
277 | |
278 | if (0 != poa->sObjectName.GetStringLength()) |
279 | { |
280 | SHMPTR shmObjectListHead = NULL; |
281 | |
282 | // |
283 | // The object must be shared |
284 | // |
285 | |
286 | _ASSERTE(fShared); |
287 | |
288 | // |
289 | // Check if an object by this name alredy exists |
290 | // |
291 | |
292 | palError = LocateObject( |
293 | pthr, |
294 | &poa->sObjectName, |
295 | paot, |
296 | &pobjExisting |
297 | ); |
298 | |
299 | if (NO_ERROR == palError) |
300 | { |
301 | // |
302 | // Obtain a new handle to the existing object |
303 | // |
304 | |
305 | palError = ObtainHandleForObject( |
306 | pthr, |
307 | pobjExisting, |
308 | dwRightsRequested, |
309 | fInherit, |
310 | NULL, |
311 | pHandle |
312 | ); |
313 | |
314 | if (NO_ERROR == palError) |
315 | { |
316 | // |
317 | // Transfer object reference to out param |
318 | // |
319 | |
320 | *ppobjRegistered = pobjExisting; |
321 | palError = ERROR_ALREADY_EXISTS; |
322 | } |
323 | else |
324 | { |
325 | pobjExisting->ReleaseReference(pthr); |
326 | } |
327 | |
328 | goto RegisterObjectExit; |
329 | } |
330 | else if (ERROR_INVALID_NAME != palError) |
331 | { |
332 | // |
333 | // Something different than an object not found error |
334 | // occurred. This is most likely due to a type conflict. |
335 | // |
336 | |
337 | goto RegisterObjectExit; |
338 | } |
339 | |
340 | // |
341 | // Insert the object on the named object lists |
342 | // |
343 | |
344 | InsertTailList(&m_leNamedObjects, pshmobj->GetObjectListLink()); |
345 | |
346 | psmodNew = SHMPTR_TO_TYPED_PTR(SHMObjData, pshmobj->GetShmObjData()); |
347 | if (NULL == psmodNew) |
348 | { |
349 | ASSERT("Failure to map shared object data\n" ); |
350 | palError = ERROR_INTERNAL_ERROR; |
351 | goto RegisterObjectExit; |
352 | } |
353 | |
354 | shmObjectListHead = SHMGetInfo(SIID_NAMED_OBJECTS); |
355 | if (NULL != shmObjectListHead) |
356 | { |
357 | SHMObjData *psmodListHead; |
358 | |
359 | psmodListHead = SHMPTR_TO_TYPED_PTR(SHMObjData, shmObjectListHead); |
360 | if (NULL != psmodListHead) |
361 | { |
362 | psmodNew->shmNextObj = shmObjectListHead; |
363 | psmodListHead->shmPrevObj = pshmobj->GetShmObjData(); |
364 | } |
365 | else |
366 | { |
367 | ASSERT("Failure to map shared object data\n" ); |
368 | palError = ERROR_INTERNAL_ERROR; |
369 | goto RegisterObjectExit; |
370 | } |
371 | } |
372 | |
373 | psmodNew->fAddedToList = TRUE; |
374 | |
375 | if (!SHMSetInfo(SIID_NAMED_OBJECTS, pshmobj->GetShmObjData())) |
376 | { |
377 | ASSERT("Failed to set shared named object list head\n" ); |
378 | palError = ERROR_INTERNAL_ERROR; |
379 | goto RegisterObjectExit; |
380 | } |
381 | } |
382 | else |
383 | { |
384 | // |
385 | // Place the object on the anonymous object list |
386 | // |
387 | |
388 | InsertTailList(&m_leAnonymousObjects, pshmobj->GetObjectListLink()); |
389 | } |
390 | |
391 | // |
392 | // Hoist the object's immutable data (if any) into shared memory if |
393 | // the object is shared |
394 | // |
395 | |
396 | if (fShared && 0 != potObj->GetImmutableDataSize()) |
397 | { |
398 | VOID *pvImmutableData; |
399 | SHMObjData *psmod; |
400 | |
401 | palError = pobjToRegister->GetImmutableData(&pvImmutableData); |
402 | if (NO_ERROR != palError) |
403 | { |
404 | ASSERT("Failure to obtain object immutable data\n" ); |
405 | goto RegisterObjectExit; |
406 | } |
407 | |
408 | psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, pshmobj->GetShmObjData()); |
409 | if (NULL != psmod) |
410 | { |
411 | VOID *pvSharedImmutableData = |
412 | SHMPTR_TO_TYPED_PTR(VOID, psmod->shmObjImmutableData); |
413 | |
414 | if (NULL != pvSharedImmutableData) |
415 | { |
416 | CopyMemory( |
417 | pvSharedImmutableData, |
418 | pvImmutableData, |
419 | potObj->GetImmutableDataSize() |
420 | ); |
421 | |
422 | if (NULL != potObj->GetImmutableDataCopyRoutine()) |
423 | { |
424 | (*potObj->GetImmutableDataCopyRoutine())(pvImmutableData, pvSharedImmutableData); |
425 | } |
426 | |
427 | psmod->pCopyRoutine = potObj->GetImmutableDataCopyRoutine(); |
428 | psmod->pCleanupRoutine = potObj->GetImmutableDataCleanupRoutine(); |
429 | } |
430 | else |
431 | { |
432 | ASSERT("Failure to map psmod->shmObjImmutableData\n" ); |
433 | palError = ERROR_INTERNAL_ERROR; |
434 | goto RegisterObjectExit; |
435 | } |
436 | } |
437 | else |
438 | { |
439 | ASSERT("Failure to map pshmobj->GetShmObjData()\n" ); |
440 | palError = ERROR_INTERNAL_ERROR; |
441 | goto RegisterObjectExit; |
442 | } |
443 | } |
444 | |
445 | // |
446 | // Obtain a handle for the new object |
447 | // |
448 | |
449 | palError = ObtainHandleForObject( |
450 | pthr, |
451 | pobjToRegister, |
452 | dwRightsRequested, |
453 | fInherit, |
454 | NULL, |
455 | pHandle |
456 | ); |
457 | |
458 | if (NO_ERROR == palError) |
459 | { |
460 | // |
461 | // Transfer pobjToRegister reference to out param |
462 | // |
463 | |
464 | *ppobjRegistered = pobjToRegister; |
465 | pobjToRegister = NULL; |
466 | } |
467 | |
468 | RegisterObjectExit: |
469 | |
470 | if (fShared) |
471 | { |
472 | SHMRelease(); |
473 | } |
474 | |
475 | InternalLeaveCriticalSection(pthr, &m_csListLock); |
476 | |
477 | if (NULL != pobjToRegister) |
478 | { |
479 | pobjToRegister->ReleaseReference(pthr); |
480 | } |
481 | |
482 | LOGEXIT("CSharedMemoryObjectManager::RegisterObject return %d\n" , palError); |
483 | |
484 | return palError; |
485 | } |
486 | |
487 | /*++ |
488 | Function: |
489 | CSharedMemoryObjectManager::LocateObject |
490 | |
491 | Search for a previously registered object with a give name and type |
492 | |
493 | Distinguished return values: |
494 | ERROR_INVALID_NAME -- no object with the specified name was previously |
495 | registered |
496 | ERROR_INVALID_HANDLE -- an object with the specified name was previously |
497 | registered, but its type is not compatible |
498 | |
499 | Parameters: |
500 | pthr -- thread data for calling thread |
501 | psObjectToLocate -- the name of the object to locate |
502 | paot -- acceptable types for the object |
503 | ppobj -- on success, receives a reference to the object instance |
504 | --*/ |
505 | |
506 | PAL_ERROR |
507 | CSharedMemoryObjectManager::LocateObject( |
508 | CPalThread *pthr, |
509 | CPalString *psObjectToLocate, |
510 | CAllowedObjectTypes *paot, |
511 | IPalObject **ppobj // OUT |
512 | ) |
513 | { |
514 | PAL_ERROR palError = NO_ERROR; |
515 | IPalObject *pobjExisting = NULL; |
516 | SHMPTR shmSharedObjectData = NULL; |
517 | SHMPTR shmObjectListEntry = NULL; |
518 | SHMObjData *psmod = NULL; |
519 | LPWSTR pwsz = NULL; |
520 | |
521 | _ASSERTE(NULL != pthr); |
522 | _ASSERTE(NULL != psObjectToLocate); |
523 | _ASSERTE(NULL != psObjectToLocate->GetString()); |
524 | _ASSERTE(PAL_wcslen(psObjectToLocate->GetString()) == psObjectToLocate->GetStringLength()); |
525 | _ASSERTE(NULL != ppobj); |
526 | |
527 | ENTRY("CSharedMemoryObjectManager::LocateObject " |
528 | "(this=%p, pthr=%p, psObjectToLocate=%p, paot=%p, " |
529 | "ppobj=%p)\n" , |
530 | this, |
531 | pthr, |
532 | psObjectToLocate, |
533 | paot, |
534 | ppobj |
535 | ); |
536 | |
537 | TRACE("Searching for object name %S\n" , psObjectToLocate->GetString()); |
538 | |
539 | InternalEnterCriticalSection(pthr, &m_csListLock); |
540 | |
541 | // |
542 | // Search the local named object list for this object |
543 | // |
544 | |
545 | for (PLIST_ENTRY ple = m_leNamedObjects.Flink; |
546 | ple != &m_leNamedObjects; |
547 | ple = ple->Flink) |
548 | { |
549 | CObjectAttributes *poa; |
550 | CSharedMemoryObject *pshmobj = |
551 | CSharedMemoryObject::GetObjectFromListLink(ple); |
552 | |
553 | poa = pshmobj->GetObjectAttributes(); |
554 | _ASSERTE(NULL != poa); |
555 | |
556 | if (poa->sObjectName.GetStringLength() != psObjectToLocate->GetStringLength()) |
557 | { |
558 | continue; |
559 | } |
560 | |
561 | if (0 != PAL_wcscmp(poa->sObjectName.GetString(), psObjectToLocate->GetString())) |
562 | { |
563 | continue; |
564 | } |
565 | |
566 | // |
567 | // This object has the name we're looking for |
568 | // |
569 | |
570 | pobjExisting = static_cast<IPalObject*>(pshmobj); |
571 | break; |
572 | } |
573 | |
574 | if (NULL != pobjExisting) |
575 | { |
576 | // |
577 | // Validate the located object's type |
578 | // |
579 | |
580 | if (paot->IsTypeAllowed( |
581 | pobjExisting->GetObjectType()->GetId() |
582 | )) |
583 | { |
584 | TRACE("Local object exists with compatible type\n" ); |
585 | |
586 | // |
587 | // Add a reference to the found object |
588 | // |
589 | |
590 | pobjExisting->AddReference(); |
591 | *ppobj = pobjExisting; |
592 | } |
593 | else |
594 | { |
595 | TRACE("Local object exists w/ incompatible type\n" ); |
596 | palError = ERROR_INVALID_HANDLE; |
597 | } |
598 | |
599 | goto LocateObjectExit; |
600 | } |
601 | |
602 | // |
603 | // Search the shared memory named object list for a matching object |
604 | // |
605 | |
606 | SHMLock(); |
607 | |
608 | shmObjectListEntry = SHMGetInfo(SIID_NAMED_OBJECTS); |
609 | while (NULL != shmObjectListEntry) |
610 | { |
611 | psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, shmObjectListEntry); |
612 | if (NULL != psmod) |
613 | { |
614 | if (psmod->dwNameLength == psObjectToLocate->GetStringLength()) |
615 | { |
616 | pwsz = SHMPTR_TO_TYPED_PTR(WCHAR, psmod->shmObjName); |
617 | if (NULL != pwsz) |
618 | { |
619 | if (0 == PAL_wcscmp(pwsz, psObjectToLocate->GetString())) |
620 | { |
621 | // |
622 | // This is the object we were looking for. |
623 | // |
624 | |
625 | shmSharedObjectData = shmObjectListEntry; |
626 | break; |
627 | } |
628 | } |
629 | else |
630 | { |
631 | ASSERT("Unable to map psmod->shmObjName\n" ); |
632 | break; |
633 | } |
634 | } |
635 | |
636 | shmObjectListEntry = psmod->shmNextObj; |
637 | } |
638 | else |
639 | { |
640 | ASSERT("Unable to map shmObjectListEntry\n" ); |
641 | break; |
642 | } |
643 | } |
644 | |
645 | if (NULL != shmSharedObjectData) |
646 | { |
647 | CSharedMemoryObject *pshmobj = NULL; |
648 | CObjectAttributes oa(pwsz, NULL); |
649 | |
650 | // |
651 | // Check if the type is allowed |
652 | // |
653 | |
654 | if (!paot->IsTypeAllowed(psmod->eTypeId)) |
655 | { |
656 | TRACE("Remote object exists w/ incompatible type\n" ); |
657 | palError = ERROR_INVALID_HANDLE; |
658 | goto LocateObjectExitSHMRelease; |
659 | } |
660 | |
661 | // |
662 | // Get the local instance of the CObjectType |
663 | // |
664 | |
665 | CObjectType *pot = CObjectType::GetObjectTypeById(psmod->eTypeId); |
666 | if (NULL == pot) |
667 | { |
668 | ASSERT("Invalid object type ID in shared memory info\n" ); |
669 | goto LocateObjectExitSHMRelease; |
670 | } |
671 | |
672 | TRACE("Remote object exists compatible type -- importing\n" ); |
673 | |
674 | // |
675 | // Create the local state for the shared object |
676 | // |
677 | |
678 | palError = ImportSharedObjectIntoProcess( |
679 | pthr, |
680 | pot, |
681 | &oa, |
682 | shmSharedObjectData, |
683 | psmod, |
684 | TRUE, |
685 | &pshmobj |
686 | ); |
687 | |
688 | if (NO_ERROR == palError) |
689 | { |
690 | *ppobj = static_cast<IPalObject*>(pshmobj); |
691 | } |
692 | else |
693 | { |
694 | ERROR("Failure initializing object from shared data\n" ); |
695 | goto LocateObjectExitSHMRelease; |
696 | } |
697 | |
698 | } |
699 | else |
700 | { |
701 | // |
702 | // The object was not found |
703 | // |
704 | |
705 | palError = ERROR_INVALID_NAME; |
706 | } |
707 | |
708 | LocateObjectExitSHMRelease: |
709 | |
710 | SHMRelease(); |
711 | |
712 | LocateObjectExit: |
713 | |
714 | InternalLeaveCriticalSection(pthr, &m_csListLock); |
715 | |
716 | LOGEXIT("CSharedMemoryObjectManager::LocateObject returns %d\n" , palError); |
717 | |
718 | return palError; |
719 | } |
720 | |
721 | /*++ |
722 | Function: |
723 | CSharedMemoryObjectManager::ObtainHandleForObject |
724 | |
725 | Allocated a new handle for an object |
726 | |
727 | Parameters: |
728 | pthr -- thread data for calling thread |
729 | pobj -- the object to allocate a handle for |
730 | dwRightsRequired -- the access rights to grant the handle; currently ignored |
731 | fInheritHandle -- true if the handle is inheritable; ignored for all but file |
732 | objects that represent pipes |
733 | pProcessForHandle -- the process the handle is to be used from; currently |
734 | must be NULL |
735 | pNewHandle -- on success, receives the newly allocated handle |
736 | --*/ |
737 | |
738 | PAL_ERROR |
739 | CSharedMemoryObjectManager::ObtainHandleForObject( |
740 | CPalThread *pthr, |
741 | IPalObject *pobj, |
742 | DWORD dwRightsRequested, |
743 | bool fInheritHandle, |
744 | IPalProcess *pProcessForHandle, // IN, OPTIONAL |
745 | HANDLE *pNewHandle // OUT |
746 | ) |
747 | { |
748 | PAL_ERROR palError = NO_ERROR; |
749 | |
750 | _ASSERTE(NULL != pthr); |
751 | _ASSERTE(NULL != pobj); |
752 | _ASSERTE(NULL != pNewHandle); |
753 | |
754 | ENTRY("CSharedMemoryObjectManager::ObtainHandleForObject " |
755 | "(this=%p, pthr=%p, pobj=%p, dwRightsRequested=%d, " |
756 | "fInheritHandle=%p, pProcessForHandle=%p, pNewHandle=%p)\n" , |
757 | this, |
758 | pthr, |
759 | pobj, |
760 | dwRightsRequested, |
761 | fInheritHandle, |
762 | pProcessForHandle, |
763 | pNewHandle |
764 | ); |
765 | |
766 | if (NULL != pProcessForHandle) |
767 | { |
768 | // |
769 | // Not yet supported |
770 | // |
771 | |
772 | ASSERT("Caller to ObtainHandleForObject provided a process\n" ); |
773 | return ERROR_CALL_NOT_IMPLEMENTED; |
774 | } |
775 | |
776 | palError = m_HandleManager.AllocateHandle( |
777 | pthr, |
778 | pobj, |
779 | dwRightsRequested, |
780 | fInheritHandle, |
781 | pNewHandle |
782 | ); |
783 | |
784 | LOGEXIT("CSharedMemoryObjectManager::ObtainHandleForObject return %d\n" , palError); |
785 | |
786 | return palError; |
787 | } |
788 | |
789 | /*++ |
790 | Function: |
791 | CSharedMemoryObjectManager::RevokeHandle |
792 | |
793 | Removes a handle from the process's handle table, which in turn releases |
794 | the handle's reference on the object instance it refers to |
795 | |
796 | Parameters: |
797 | pthr -- thread data for calling thread |
798 | hHandleToRevoke -- the handle to revoke |
799 | --*/ |
800 | |
801 | PAL_ERROR |
802 | CSharedMemoryObjectManager::RevokeHandle( |
803 | CPalThread *pthr, |
804 | HANDLE hHandleToRevoke |
805 | ) |
806 | { |
807 | PAL_ERROR palError = NO_ERROR; |
808 | |
809 | _ASSERTE(NULL != pthr); |
810 | |
811 | ENTRY("CSharedMemoryObjectManager::RevokeHandle " |
812 | "(this=%p, pthr=%p, hHandleToRevoke=%p)\n" , |
813 | this, |
814 | pthr, |
815 | hHandleToRevoke |
816 | ); |
817 | |
818 | palError = m_HandleManager.FreeHandle(pthr, hHandleToRevoke); |
819 | |
820 | LOGEXIT("CSharedMemoryObjectManager::RevokeHandle returns %d\n" , palError); |
821 | |
822 | return palError; |
823 | } |
824 | |
825 | /*++ |
826 | Function: |
827 | CSharedMemoryObjectManager::ReferenceObjectByHandle |
828 | |
829 | Returns a referenced object instance that a handle refers to |
830 | |
831 | Parameters: |
832 | pthr -- thread data for calling thread |
833 | hHandleToReference -- the handle to reference |
834 | paot -- acceptable types for the underlying object |
835 | dwRightsRequired -- the access rights that the handle must have been |
836 | granted; currently ignored |
837 | ppobj -- on success, receives a reference to the object instance |
838 | --*/ |
839 | |
840 | PAL_ERROR |
841 | CSharedMemoryObjectManager::ReferenceObjectByHandle( |
842 | CPalThread *pthr, |
843 | HANDLE hHandleToReference, |
844 | CAllowedObjectTypes *paot, |
845 | DWORD dwRightsRequired, |
846 | IPalObject **ppobj // OUT |
847 | ) |
848 | { |
849 | PAL_ERROR palError; |
850 | DWORD dwRightsGranted; |
851 | IPalObject *pobj; |
852 | |
853 | _ASSERTE(NULL != pthr); |
854 | _ASSERTE(NULL != paot); |
855 | _ASSERTE(NULL != ppobj); |
856 | |
857 | ENTRY("CSharedMemoryObjectManager::ReferenceObjectByHandle " |
858 | "(this=%p, pthr=%p, hHandleToReference=%p, paot=%p, " |
859 | "dwRightsRequired=%d, ppobj=%p)\n" , |
860 | this, |
861 | pthr, |
862 | hHandleToReference, |
863 | paot, |
864 | dwRightsRequired, |
865 | ppobj |
866 | ); |
867 | |
868 | palError = m_HandleManager.GetObjectFromHandle( |
869 | pthr, |
870 | hHandleToReference, |
871 | &dwRightsGranted, |
872 | &pobj |
873 | ); |
874 | |
875 | if (NO_ERROR == palError) |
876 | { |
877 | palError = CheckObjectTypeAndRights( |
878 | pobj, |
879 | paot, |
880 | dwRightsGranted, |
881 | dwRightsRequired |
882 | ); |
883 | |
884 | if (NO_ERROR == palError) |
885 | { |
886 | // |
887 | // Transfer object reference to out parameter |
888 | // |
889 | |
890 | *ppobj = pobj; |
891 | } |
892 | else |
893 | { |
894 | pobj->ReleaseReference(pthr); |
895 | } |
896 | } |
897 | |
898 | LOGEXIT("CSharedMemoryObjectManager::ReferenceObjectByHandle returns %d\n" , |
899 | palError |
900 | ); |
901 | |
902 | return palError; |
903 | } |
904 | |
905 | /*++ |
906 | Function: |
907 | CSharedMemoryObjectManager::ReferenceObjectByHandleArray |
908 | |
909 | Returns the referenced object instances that an array of handles |
910 | refer to. |
911 | |
912 | Parameters: |
913 | pthr -- thread data for calling thread |
914 | rgHandlesToReference -- the array of handles to reference |
915 | dwHandleCount -- the number of handles in the arrayu |
916 | paot -- acceptable types for the underlying objects |
917 | dwRightsRequired -- the access rights that the handles must have been |
918 | granted; currently ignored |
919 | rgpobjs -- on success, receives references to the object instances; will |
920 | be empty on failures |
921 | --*/ |
922 | |
923 | PAL_ERROR |
924 | CSharedMemoryObjectManager::ReferenceMultipleObjectsByHandleArray( |
925 | CPalThread *pthr, |
926 | HANDLE rghHandlesToReference[], |
927 | DWORD dwHandleCount, |
928 | CAllowedObjectTypes *paot, |
929 | DWORD dwRightsRequired, |
930 | IPalObject *rgpobjs[] // OUT (caller allocated) |
931 | ) |
932 | { |
933 | PAL_ERROR palError = NO_ERROR; |
934 | IPalObject *pobj = NULL; |
935 | DWORD dwRightsGranted; |
936 | DWORD dw; |
937 | |
938 | _ASSERTE(NULL != pthr); |
939 | _ASSERTE(NULL != rghHandlesToReference); |
940 | _ASSERTE(0 < dwHandleCount); |
941 | _ASSERTE(NULL != paot); |
942 | _ASSERTE(NULL != rgpobjs); |
943 | |
944 | ENTRY("CSharedMemoryObjectManager::ReferenceMultipleObjectsByHandleArray " |
945 | "(this=%p, pthr=%p, rghHandlesToReference=%p, dwHandleCount=%d, " |
946 | "pAllowedTyped=%d, dwRightsRequired=%d, rgpobjs=%p)\n" , |
947 | this, |
948 | pthr, |
949 | rghHandlesToReference, |
950 | dwHandleCount, |
951 | paot, |
952 | dwRightsRequired, |
953 | rgpobjs |
954 | ); |
955 | |
956 | m_HandleManager.Lock(pthr); |
957 | |
958 | for (dw = 0; dw < dwHandleCount; dw += 1) |
959 | { |
960 | palError = m_HandleManager.GetObjectFromHandle( |
961 | pthr, |
962 | rghHandlesToReference[dw], |
963 | &dwRightsGranted, |
964 | &pobj |
965 | ); |
966 | |
967 | if (NO_ERROR == palError) |
968 | { |
969 | palError = CheckObjectTypeAndRights( |
970 | pobj, |
971 | paot, |
972 | dwRightsGranted, |
973 | dwRightsRequired |
974 | ); |
975 | |
976 | if (NO_ERROR == palError) |
977 | { |
978 | // |
979 | // Transfer reference to out array |
980 | // |
981 | |
982 | rgpobjs[dw] = pobj; |
983 | pobj = NULL; |
984 | } |
985 | } |
986 | |
987 | if (NO_ERROR != palError) |
988 | { |
989 | break; |
990 | } |
991 | } |
992 | |
993 | // |
994 | // The handle manager lock must be released before releasing |
995 | // any object references, as ReleaseReference will acquire |
996 | // the object manager list lock (which needs to be acquired before |
997 | // the handle manager lock) |
998 | // |
999 | |
1000 | m_HandleManager.Unlock(pthr); |
1001 | |
1002 | if (NO_ERROR != palError) |
1003 | { |
1004 | // |
1005 | // dw's current value is the failing index, so we want |
1006 | // to free from dw - 1. |
1007 | // |
1008 | |
1009 | while (dw > 0) |
1010 | { |
1011 | rgpobjs[--dw]->ReleaseReference(pthr); |
1012 | } |
1013 | |
1014 | if (NULL != pobj) |
1015 | { |
1016 | pobj->ReleaseReference(pthr); |
1017 | } |
1018 | } |
1019 | |
1020 | LOGEXIT("CSharedMemoryObjectManager::ReferenceMultipleObjectsByHandleArray" |
1021 | " returns %d\n" , |
1022 | palError |
1023 | ); |
1024 | |
1025 | return palError; |
1026 | } |
1027 | |
1028 | /*++ |
1029 | Function: |
1030 | CSharedMemoryObjectManager::ReferenceObjectByForeignHandle |
1031 | |
1032 | Returns a referenced object instance that a handle belongin to |
1033 | another process refers to; currently unimplemented |
1034 | |
1035 | Parameters: |
1036 | pthr -- thread data for calling thread |
1037 | hForeignHandle -- the handle to reference |
1038 | pForeignProcess -- the process that hForeignHandle belongs to |
1039 | paot -- acceptable types for the underlying object |
1040 | dwRightsRequired -- the access rights that the handle must have been |
1041 | granted; currently ignored |
1042 | ppobj -- on success, receives a reference to the object instance |
1043 | --*/ |
1044 | |
1045 | PAL_ERROR |
1046 | CSharedMemoryObjectManager::ReferenceObjectByForeignHandle( |
1047 | CPalThread *pthr, |
1048 | HANDLE hForeignHandle, |
1049 | IPalProcess *pForeignProcess, |
1050 | CAllowedObjectTypes *paot, |
1051 | DWORD dwRightsRequired, |
1052 | IPalObject **ppobj // OUT |
1053 | ) |
1054 | { |
1055 | // |
1056 | // Not implemented for basic shared memory object manager -- |
1057 | // requires an IPC channel. (For the shared memory object manager |
1058 | // PAL_LocalHandleToRemote and PAL_RemoteHandleToLocal must still |
1059 | // be used...) |
1060 | // |
1061 | |
1062 | ASSERT("ReferenceObjectByForeignHandle not yet supported\n" ); |
1063 | return ERROR_CALL_NOT_IMPLEMENTED; |
1064 | } |
1065 | |
1066 | /*++ |
1067 | Function: |
1068 | CSharedMemoryObjectManager::ImportSharedObjectIntoProcess |
1069 | |
1070 | Takes an object's shared memory data and from it creates the |
1071 | necessary in-process structures for the object |
1072 | |
1073 | Parameters: |
1074 | pthr -- thread data for calling thread |
1075 | pot -- the object's type |
1076 | poa -- attributes for the object |
1077 | shmSharedObjectData -- the shared memory pointer for the object's shared |
1078 | data |
1079 | psmod -- the shared memory data for the object, mapped into this process's |
1080 | address space |
1081 | fAddRefSharedData -- if TRUE, we need to add to the shared data reference |
1082 | count |
1083 | ppshmobj -- on success, receives a pointer to the newly created local |
1084 | object instance |
1085 | --*/ |
1086 | |
1087 | PAL_ERROR |
1088 | CSharedMemoryObjectManager::ImportSharedObjectIntoProcess( |
1089 | CPalThread *pthr, |
1090 | CObjectType *pot, |
1091 | CObjectAttributes *poa, |
1092 | SHMPTR shmSharedObjectData, |
1093 | SHMObjData *psmod, |
1094 | bool fAddRefSharedData, |
1095 | CSharedMemoryObject **ppshmobj |
1096 | ) |
1097 | { |
1098 | PAL_ERROR palError = NO_ERROR; |
1099 | CSharedMemoryObject *pshmobj; |
1100 | PLIST_ENTRY pleObjectList; |
1101 | |
1102 | _ASSERTE(NULL != pthr); |
1103 | _ASSERTE(NULL != pot); |
1104 | _ASSERTE(NULL != poa); |
1105 | _ASSERTE(NULL != shmSharedObjectData); |
1106 | _ASSERTE(NULL != psmod); |
1107 | _ASSERTE(NULL != ppshmobj); |
1108 | |
1109 | ENTRY("CSharedMemoryObjectManager::ImportSharedObjectIntoProcess(pthr=%p, " |
1110 | "pot=%p, poa=%p, shmSharedObjectData=%p, psmod=%p, fAddRefSharedData=%d, " |
1111 | "ppshmobj=%p)\n" , |
1112 | pthr, |
1113 | pot, |
1114 | poa, |
1115 | shmSharedObjectData, |
1116 | psmod, |
1117 | fAddRefSharedData, |
1118 | ppshmobj |
1119 | ); |
1120 | |
1121 | if (CObjectType::WaitableObject == pot->GetSynchronizationSupport()) |
1122 | { |
1123 | pshmobj = InternalNew<CSharedMemoryWaitableObject>(pot, |
1124 | &m_csListLock, |
1125 | shmSharedObjectData, |
1126 | psmod, |
1127 | fAddRefSharedData); |
1128 | } |
1129 | else |
1130 | { |
1131 | pshmobj = InternalNew<CSharedMemoryObject>(pot, |
1132 | &m_csListLock, |
1133 | shmSharedObjectData, |
1134 | psmod, |
1135 | fAddRefSharedData); |
1136 | } |
1137 | |
1138 | if (NULL != pshmobj) |
1139 | { |
1140 | palError = pshmobj->InitializeFromExistingSharedData(pthr, poa); |
1141 | if (NO_ERROR == palError) |
1142 | { |
1143 | if (0 != psmod->dwNameLength) |
1144 | { |
1145 | pleObjectList = &m_leNamedObjects; |
1146 | } |
1147 | else |
1148 | { |
1149 | pleObjectList = &m_leAnonymousObjects; |
1150 | } |
1151 | |
1152 | InsertTailList(pleObjectList, pshmobj->GetObjectListLink()); |
1153 | } |
1154 | else |
1155 | { |
1156 | goto ImportSharedObjectIntoProcessExit; |
1157 | } |
1158 | } |
1159 | else |
1160 | { |
1161 | ERROR("Unable to allocate new object\n" ); |
1162 | palError = ERROR_OUTOFMEMORY; |
1163 | goto ImportSharedObjectIntoProcessExit; |
1164 | } |
1165 | |
1166 | *ppshmobj = pshmobj; |
1167 | |
1168 | ImportSharedObjectIntoProcessExit: |
1169 | |
1170 | LOGEXIT("CSharedMemoryObjectManager::ImportSharedObjectIntoProcess returns %d\n" , palError); |
1171 | |
1172 | return palError; |
1173 | } |
1174 | |
1175 | static PalObjectTypeId RemotableObjectTypes[] = |
1176 | {otiManualResetEvent, otiAutoResetEvent, otiMutex, otiProcess}; |
1177 | |
1178 | static CAllowedObjectTypes aotRemotable( |
1179 | RemotableObjectTypes, |
1180 | sizeof(RemotableObjectTypes) / sizeof(RemotableObjectTypes[0]) |
1181 | ); |
1182 | |
1183 | /*++ |
1184 | Function: |
1185 | CheckObjectTypeAndRights |
1186 | |
1187 | Helper routine that determines if: |
1188 | 1) An object instance is of a specified type |
1189 | 2) A set of granted access rights satisfies the required access rights |
1190 | (currently ignored) |
1191 | |
1192 | Parameters: |
1193 | pobj -- the object instance whose type is to be checked |
1194 | paot -- the acceptable type for the object instance |
1195 | dwRightsGranted -- the granted access rights (ignored) |
1196 | dwRightsRequired -- the required access rights (ignored) |
1197 | --*/ |
1198 | |
1199 | static |
1200 | PAL_ERROR |
1201 | CheckObjectTypeAndRights( |
1202 | IPalObject *pobj, |
1203 | CAllowedObjectTypes *paot, |
1204 | DWORD dwRightsGranted, |
1205 | DWORD dwRightsRequired |
1206 | ) |
1207 | { |
1208 | PAL_ERROR palError = NO_ERROR; |
1209 | |
1210 | _ASSERTE(NULL != pobj); |
1211 | _ASSERTE(NULL != paot); |
1212 | |
1213 | ENTRY("CheckObjectTypeAndRights (pobj=%p, paot=%p, " |
1214 | "dwRightsGranted=%d, dwRightsRequired=%d)\n" , |
1215 | pobj, |
1216 | paot, |
1217 | dwRightsGranted, |
1218 | dwRightsRequired |
1219 | ); |
1220 | |
1221 | if (paot->IsTypeAllowed(pobj->GetObjectType()->GetId())) |
1222 | { |
1223 | #ifdef ENFORCE_OBJECT_ACCESS_RIGHTS |
1224 | |
1225 | // |
1226 | // This is where the access right check would occur if Win32 object |
1227 | // security were supported. |
1228 | // |
1229 | |
1230 | if ((dwRightsRequired & dwRightsGranted) != dwRightsRequired) |
1231 | { |
1232 | palError = ERROR_ACCESS_DENIED; |
1233 | } |
1234 | #endif |
1235 | } |
1236 | else |
1237 | { |
1238 | palError = ERROR_INVALID_HANDLE; |
1239 | } |
1240 | |
1241 | LOGEXIT("CheckObjectTypeAndRights returns %d\n" , palError); |
1242 | |
1243 | return palError; |
1244 | } |
1245 | |
1246 | |
1247 | |