Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit c755e3b

Browse files
authored
[Local GC] Move knowledge of overlapped I/O objects to the EE through four callbacks (#14982)
* [Local GC] Move knowledge of overlapped I/O objects to the EE through four callbacks * Code review feedback: 1. Rename OverlappedData->AsyncPinned in interface methods 2. Remove additional FEATURE_REDHAWK defines around async pin relocation code * Eliminate two GCToEEInterface callbacks by passing the callbacks directly as arguments to a method on IGCHandleStore * Repair clang build * Split pin and async pin handle scans into two separate callbacks * Fix the clang and non-Windows builds
1 parent 4e625b8 commit c755e3b

20 files changed

+287
-192
lines changed

src/gc/env/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <stdint.h>
1717
#include <stddef.h>
1818
#include <stdio.h>
19+
#include <stdlib.h>
1920
#include <string.h>
2021
#include <wchar.h>
2122
#include <assert.h>

src/gc/env/gcenv.base.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,11 @@ inline void* ALIGN_DOWN(void* ptr, size_t alignment)
320320
return reinterpret_cast<void*>(ALIGN_DOWN(as_size_t, alignment));
321321
}
322322

323+
inline int GetRandomInt(int max)
324+
{
325+
return rand() % max;
326+
}
327+
323328
typedef struct _PROCESSOR_NUMBER {
324329
uint16_t Group;
325330
uint8_t Number;

src/gc/env/gcenv.ee.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ class GCToEEInterface
8080
static bool IsGCThread();
8181
static bool WasCurrentThreadCreatedByGC();
8282
static bool CreateThread(void (*threadStart)(void*), void* arg, bool is_suspendable, const char* name);
83+
static void WalkAsyncPinnedForPromotion(Object* object, ScanContext* sc, promote_func* callback);
84+
static void WalkAsyncPinned(Object* object, void* context, void(*callback)(Object*, Object*, void*));
8385
};
8486

8587
#endif // __GCENV_EE_H__

src/gc/gcenv.ee.standalone.inl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,5 +258,16 @@ inline bool GCToEEInterface::CreateThread(void (*threadStart)(void*), void* arg,
258258
return g_theGCToCLR->CreateThread(threadStart, arg, is_suspendable, name);
259259
}
260260

261+
inline void GCToEEInterface::WalkAsyncPinnedForPromotion(Object* object, ScanContext* sc, promote_func* callback)
262+
{
263+
assert(g_theGCToCLR != nullptr);
264+
return g_theGCToCLR->WalkAsyncPinnedForPromotion(object, sc, callback);
265+
}
266+
267+
inline void GCToEEInterface::WalkAsyncPinned(Object* object, void* context, void(*callback)(Object*, Object*, void*))
268+
{
269+
assert(g_theGCToCLR != nullptr);
270+
return g_theGCToCLR->WalkAsyncPinned(object, context, callback);
271+
}
261272

262273
#endif // __GCTOENV_EE_STANDALONE_INL__

src/gc/gchandletable.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ OBJECTHANDLE GCHandleStore::CreateDependentHandle(Object* primary, Object* secon
5757
return handle;
5858
}
5959

60-
void GCHandleStore::RelocateAsyncPinnedHandles(IGCHandleStore* pTarget)
60+
void GCHandleStore::RelocateAsyncPinnedHandles(IGCHandleStore* pTarget, void (*clearIfComplete)(Object*), void (*setHandle)(Object*, OBJECTHANDLE))
6161
{
6262
// assumption - the IGCHandleStore is an instance of GCHandleStore
6363
GCHandleStore* other = static_cast<GCHandleStore*>(pTarget);
64-
::Ref_RelocateAsyncPinHandles(&_underlyingBucket, &other->_underlyingBucket);
64+
::Ref_RelocateAsyncPinHandles(&_underlyingBucket, &other->_underlyingBucket, clearIfComplete, setHandle);
6565
}
6666

6767
bool GCHandleStore::EnumerateAsyncPinnedHandles(async_pin_enum_fn callback, void* context)

src/gc/gchandletableimpl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class GCHandleStore : public IGCHandleStore
2323

2424
virtual OBJECTHANDLE CreateDependentHandle(Object* primary, Object* secondary);
2525

26-
virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget);
26+
virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget, void (*clearIfCompleteCallback)(Object* object), void (*setHandle)(Object* object, OBJECTHANDLE handle));
2727

2828
virtual bool EnumerateAsyncPinnedHandles(async_pin_enum_fn callback, void* context);
2929

src/gc/gcinterface.ee.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,38 @@ class IGCToCLR {
219219
// or a server GC thread.
220220
virtual
221221
bool WasCurrentThreadCreatedByGC() = 0;
222+
223+
// Given an object, if this object is an instance of `System.Threading.OverlappedData`,
224+
// and the runtime treats instances of this class specially, traverses the objects that
225+
// are directly or (once) indirectly pinned by this object and reports them to the GC for
226+
// the purposes of relocation and promotion.
227+
//
228+
// Overlapped objects are very special and as such the objects they wrap can't be promoted in
229+
// the same manner as normal objects. This callback gives the EE the opportunity to hide these
230+
// details, if they are implemented at all.
231+
//
232+
// This function is a no-op if "object" is not an OverlappedData object.
233+
virtual
234+
void WalkAsyncPinnedForPromotion(Object* object, ScanContext* sc, promote_func* callback) = 0;
235+
236+
// Given an object, if this object is an instance of `System.Threading.OverlappedData` and the
237+
// runtime treats instances of this class specially, traverses the objects that are directly
238+
// or once indirectly pinned by this object and invokes the given callback on them. The callback
239+
// is passed the following arguments:
240+
// Object* "from" - The object that "caused" the "to" object to be pinned. If a single object
241+
// is pinned directly by this OverlappedData, this object will be the
242+
// OverlappedData object itself. If an array is pinned by this OverlappedData,
243+
// this object will be the pinned array.
244+
// Object* "to" - The object that is pinned by the "from" object. If a single object is pinned
245+
// by an OverlappedData, "to" will be that single object. If an array is pinned
246+
// by an OverlappedData, the callback will be invoked on all elements of that
247+
// array and each element will be a "to" object.
248+
// void* "context" - Passed verbatim from "WalkOverlappedObject" to the callback function.
249+
// The "context" argument will be passed directly to the callback without modification or inspection.
250+
//
251+
// This function is a no-op if "object" is not an OverlappedData object.
252+
virtual
253+
void WalkAsyncPinned(Object* object, void* context, void(*callback)(Object*, Object*, void*)) = 0;
222254
};
223255

224256
#endif // _GCINTERFACE_EE_H_

src/gc/gcinterface.h

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,17 @@ struct WriteBarrierParameters
111111
uint8_t* write_watch_table;
112112
};
113113

114+
// Opaque type for tracking object pointers
115+
#ifndef DACCESS_COMPILE
116+
struct OBJECTHANDLE__
117+
{
118+
void* unused;
119+
};
120+
typedef struct OBJECTHANDLE__* OBJECTHANDLE;
121+
#else
122+
typedef uintptr_t OBJECTHANDLE;
123+
#endif
124+
114125
/*
115126
* Scanning callback.
116127
*/
@@ -393,16 +404,7 @@ typedef void (* fq_scan_fn)(Object** ppObject, ScanContext *pSC, uint32_t dwFlag
393404
typedef void (* handle_scan_fn)(Object** pRef, Object* pSec, uint32_t flags, ScanContext* context, bool isDependent);
394405
typedef bool (* async_pin_enum_fn)(Object* object, void* context);
395406

396-
// Opaque type for tracking object pointers
397-
#ifndef DACCESS_COMPILE
398-
struct OBJECTHANDLE__
399-
{
400-
void* unused;
401-
};
402-
typedef struct OBJECTHANDLE__* OBJECTHANDLE;
403-
#else
404-
typedef uintptr_t OBJECTHANDLE;
405-
#endif
407+
406408

407409
class IGCHandleStore {
408410
public:
@@ -419,7 +421,14 @@ class IGCHandleStore {
419421

420422
virtual OBJECTHANDLE CreateDependentHandle(Object* primary, Object* secondary) = 0;
421423

422-
virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget) = 0;
424+
// Relocates async pinned handles from a condemned handle store to the default domain's handle store.
425+
//
426+
// The two callbacks are called when:
427+
// 1. clearIfComplete is called whenever the handle table observes an async pin that is still live.
428+
// The callback gives a chance for the EE to unpin the referents if the overlapped operation is complete.
429+
// 2. setHandle is called whenever the GC has relocated the async pin to a new handle table. The passed-in
430+
// handle is the newly-allocated handle in the default domain that should be assigned to the overlapped object.
431+
virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget, void (*clearIfComplete)(Object*), void (*setHandle)(Object*, OBJECTHANDLE)) = 0;
423432

424433
virtual bool EnumerateAsyncPinnedHandles(async_pin_enum_fn callback, void* context) = 0;
425434

src/gc/handletable.cpp

Lines changed: 26 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@
2020
#include "objecthandle.h"
2121
#include "handletablepriv.h"
2222

23-
#ifndef FEATURE_REDHAWK
24-
#include "nativeoverlapped.h"
25-
#endif
26-
2723
/****************************************************************************
2824
*
2925
* FORWARD DECLARATIONS
@@ -626,34 +622,31 @@ void HndLogSetEvent(OBJECTHANDLE handle, _UNCHECKED_OBJECTREF value)
626622
FireEtwSetGCHandle((void*) handle, value, hndType, generation, (int64_t) pAppDomain, GetClrInstanceId());
627623
FireEtwPrvSetGCHandle((void*) handle, value, hndType, generation, (int64_t) pAppDomain, GetClrInstanceId());
628624

629-
#ifndef FEATURE_REDHAWK
630625
// Also fire the things pinned by Async pinned handles
631626
if (hndType == HNDTYPE_ASYNCPINNED)
632627
{
633-
if (value->GetMethodTable() == g_pOverlappedDataClass)
628+
// the closure passed to "WalkOverlappedObject" is not permitted to implicitly
629+
// capture any variables in this scope, since WalkForOverlappedObject takes a bare
630+
// function pointer and context pointer as arguments. We can still /explicitly/
631+
// close over values in this scope by doing what the compiler would do and introduce
632+
// a structure that contains all of the things we closed over, while passing a pointer
633+
// to this structure as our closure's context pointer.
634+
struct ClosureCapture
634635
{
635-
OverlappedDataObject* overlapped = (OverlappedDataObject*) value;
636-
if (overlapped->m_isArray)
637-
{
638-
ArrayBase* pUserObject = (ArrayBase*)OBJECTREFToObject(overlapped->m_userObject);
639-
Object **ppObj = (Object**)pUserObject->GetDataPtr(TRUE);
640-
size_t num = pUserObject->GetNumComponents();
641-
for (size_t i = 0; i < num; i ++)
642-
{
643-
value = ppObj[i];
644-
uint32_t generation = value != 0 ? g_theGCHeap->WhichGeneration(value) : 0;
645-
FireEtwSetGCHandle(overlapped, value, HNDTYPE_PINNED, generation, (int64_t) pAppDomain, GetClrInstanceId());
646-
}
647-
}
648-
else
649-
{
650-
value = OBJECTREF_TO_UNCHECKED_OBJECTREF(overlapped->m_userObject);
651-
uint32_t generation = value != 0 ? g_theGCHeap->WhichGeneration(value) : 0;
652-
FireEtwSetGCHandle(overlapped, value, HNDTYPE_PINNED, generation, (int64_t) pAppDomain, GetClrInstanceId());
653-
}
654-
}
636+
AppDomain* pAppDomain;
637+
Object* overlapped;
638+
};
639+
640+
ClosureCapture captured;
641+
captured.pAppDomain = pAppDomain;
642+
captured.overlapped = value;
643+
GCToEEInterface::WalkAsyncPinned(value, &captured, [](Object*, Object* to, void* ctx)
644+
{
645+
ClosureCapture* captured = reinterpret_cast<ClosureCapture*>(ctx);
646+
uint32_t generation = to != nullptr ? g_theGCHeap->WhichGeneration(to) : 0;
647+
FireEtwSetGCHandle(captured->overlapped, to, HNDTYPE_PINNED, generation, (int64_t) captured->pAppDomain, GetClrInstanceId());
648+
});
655649
}
656-
#endif // FEATURE_REDHAWK
657650
}
658651
#else
659652
UNREFERENCED_PARAMETER(handle);
@@ -709,14 +702,12 @@ void HndWriteBarrier(OBJECTHANDLE handle, OBJECTREF objref)
709702
int generation = g_theGCHeap->WhichGeneration(value);
710703
uint32_t uType = HandleFetchType(handle);
711704

712-
#ifndef FEATURE_REDHAWK
713705
//OverlappedData need special treatment: because all user data pointed by it needs to be reported by this handle,
714706
//its age is consider to be min age of the user data, to be simple, we just make it 0
715-
if (uType == HNDTYPE_ASYNCPINNED && objref->GetGCSafeMethodTable () == g_pOverlappedDataClass)
707+
if (uType == HNDTYPE_ASYNCPINNED)
716708
{
717709
generation = 0;
718710
}
719-
#endif // !FEATURE_REDHAWK
720711

721712
if (uType == HNDTYPE_DEPENDENT)
722713
{
@@ -1165,7 +1156,6 @@ uint32_t HndCountAllHandles(BOOL fUseLocks)
11651156

11661157
BOOL Ref_HandleAsyncPinHandles(async_pin_enum_fn asyncPinCallback, void* context)
11671158
{
1168-
#ifndef FEATURE_REDHAWK
11691159
CONTRACTL
11701160
{
11711161
NOTHROW;
@@ -1186,14 +1176,13 @@ BOOL Ref_HandleAsyncPinHandles(async_pin_enum_fn asyncPinCallback, void* contex
11861176
}
11871177

11881178
return result;
1189-
#else
1190-
return true;
1191-
#endif // !FEATURE_REDHAWK
11921179
}
11931180

1194-
void Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource, HandleTableBucket *pTarget)
1181+
void Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource,
1182+
HandleTableBucket *pTarget,
1183+
void (*clearIfComplete)(Object* object),
1184+
void (*setHandle)(Object* object, OBJECTHANDLE handle))
11951185
{
1196-
#ifndef FEATURE_REDHAWK
11971186
CONTRACTL
11981187
{
11991188
NOTHROW;
@@ -1204,9 +1193,8 @@ void Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource, HandleTableBucket
12041193
int limit = getNumberOfSlots();
12051194
for (int n = 0; n < limit; n ++ )
12061195
{
1207-
TableRelocateAsyncPinHandles(Table(pSource->pTable[n]), Table(pTarget->pTable[n]));
1196+
TableRelocateAsyncPinHandles(Table(pSource->pTable[n]), Table(pTarget->pTable[n]), clearIfComplete, setHandle);
12081197
}
1209-
#endif // !FEATURE_REDHAWK
12101198
}
12111199

12121200
/*--------------------------------------------------------------------------*/

0 commit comments

Comments
 (0)