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

[Local GC] Unify background GC thread and server GC thread creation #14821

Merged
merged 15 commits into from
Nov 9, 2017
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/gc/env/gcenv.ee.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ class GCToEEInterface
static bool CatchAtSafePoint(Thread * pThread);

static void GcEnumAllocContexts(enum_alloc_context_func* fn, void* param);

static Thread* CreateBackgroundThread(GCBackgroundThreadFunction threadStart, void* arg);

// Diagnostics methods.
static void DiagGCStart(int gen, bool isInduced);
static void DiagUpdateGenerationBounds();
Expand All @@ -82,6 +79,7 @@ class GCToEEInterface
static void FreeStringConfigValue(const char* key);
static bool IsGCThread();
static bool IsGCSpecialThread();
static bool CreateThread(void (*threadStart)(void*), void* arg, bool is_special, const wchar_t* name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would try to avoid naming things special wherever possible. special is very cryptic.

What about calling this flag suspendable?

(Also, it would be nice to rename IsGCSpecialThread to something more self-descriptive.)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do!

};

#endif // __GCENV_EE_H__
26 changes: 17 additions & 9 deletions src/gc/env/gcenv.os.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,15 +243,6 @@ class GCToOSInterface
// Thread and process
//

// Create a new thread
// Parameters:
// function - the function to be executed by the thread
// param - parameters of the thread
// affinity - processor affinity of the thread
// Return:
// true if it has succeeded, false if it has failed
static bool CreateThread(GCThreadFunction function, void* param, GCThreadAffinity* affinity);

// Causes the calling thread to sleep for the specified number of milliseconds
// Parameters:
// sleepMSec - time to sleep before switching to another thread
Expand Down Expand Up @@ -307,6 +298,23 @@ class GCToOSInterface
// The number of processors
static uint32_t GetCurrentProcessCpuCount();

// Sets the calling thread's affinity to only run on the processor specified
// in the GCThreadAffinity structure.
// Parameters:
// affinity - The requested affinity for the calling thread. At most one processor
// can be provided.
// Return:
// true if setting the affinity was successful, false otherwise.
static bool SetThreadAffinity(GCThreadAffinity* affinity);

// Boosts the calling thread's thread priority to a level higher than the default
// for new threads.
// Parameters:
// None.
// Return:
// true if the priority boost was successful, false otherwise.
static bool BoostThreadPriority();

// Get affinity mask of the current process
// Parameters:
// processMask - affinity mask for the specified process
Expand Down
68 changes: 27 additions & 41 deletions src/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5351,23 +5351,7 @@ void set_thread_affinity_mask_for_heap(int heap_number, GCThreadAffinity* affini
bool gc_heap::create_gc_thread ()
{
dprintf (3, ("Creating gc thread\n"));

GCThreadAffinity affinity;
affinity.Group = GCThreadAffinity::None;
affinity.Processor = GCThreadAffinity::None;

if (!gc_thread_no_affinitize_p)
{
// We are about to set affinity for GC threads. It is a good place to set up NUMA and
// CPU groups because the process mask, processor number, and group number are all
// readily available.
if (CPUGroupInfo::CanEnableGCCPUGroups())
set_thread_group_affinity_for_heap(heap_number, &affinity);
else
set_thread_affinity_mask_for_heap(heap_number, &affinity);
}

return GCToOSInterface::CreateThread(gc_thread_stub, this, &affinity);
return GCToEEInterface::CreateThread(gc_thread_stub, this, false, L"Server GC");
}

#ifdef _MSC_VER
Expand Down Expand Up @@ -24917,27 +24901,29 @@ void gc_heap::compact_phase (int condemned_gen_number,
#endif //_MSC_VER
void gc_heap::gc_thread_stub (void* arg)
{
ClrFlsSetThreadType (ThreadType_GC);
STRESS_LOG_RESERVE_MEM (GC_STRESSLOG_MULTIPLY);
gc_heap* heap = (gc_heap*)arg;
if (!gc_thread_no_affinitize_p)
{
GCThreadAffinity affinity;
affinity.Group = GCThreadAffinity::None;
affinity.Processor = GCThreadAffinity::None;

#ifndef FEATURE_REDHAWK
// We commit the thread's entire stack to ensure we're robust in low memory conditions.
BOOL fSuccess = Thread::CommitThreadStack(NULL);
// We are about to set affinity for GC threads. It is a good place to set up NUMA and
// CPU groups because the process mask, processor number, and group number are all
// readily available.
if (CPUGroupInfo::CanEnableGCCPUGroups())
set_thread_group_affinity_for_heap(heap->heap_number, &affinity);
else
set_thread_affinity_mask_for_heap(heap->heap_number, &affinity);

if (!fSuccess)
{
#ifdef BACKGROUND_GC
// For background GC we revert to doing a blocking GC.
return;
#else
STRESS_LOG0(LF_GC, LL_ALWAYS, "Thread::CommitThreadStack failed.");
_ASSERTE(!"Thread::CommitThreadStack failed.");
GCToEEInterface::HandleFatalError(COR_E_STACKOVERFLOW);
#endif //BACKGROUND_GC
if (!GCToOSInterface::SetThreadAffinity(&affinity))
{
dprintf(1, ("Failed to set thread affinity for server GC thread"));
}
}
#endif // FEATURE_REDHAWK

gc_heap* heap = (gc_heap*)arg;
// server GC threads run at a higher priority than normal.
GCToOSInterface::BoostThreadPriority();
_alloca (256*heap->heap_number);
heap->gc_thread_function();
}
Expand All @@ -24953,10 +24939,12 @@ void gc_heap::gc_thread_stub (void* arg)
#pragma warning(push)
#pragma warning(disable:4702) // C4702: unreachable code: gc_thread_function may not return
#endif //_MSC_VER
uint32_t __stdcall gc_heap::bgc_thread_stub (void* arg)
void gc_heap::bgc_thread_stub (void* arg)
{
gc_heap* heap = (gc_heap*)arg;
return heap->bgc_thread_function();
heap->bgc_thread = GCToEEInterface::GetThread();
assert(heap->bgc_thread != nullptr);
heap->bgc_thread_function();
}
#ifdef _MSC_VER
#pragma warning(pop)
Expand Down Expand Up @@ -26730,9 +26718,7 @@ BOOL gc_heap::create_bgc_thread(gc_heap* gh)

//dprintf (2, ("Creating BGC thread"));

gh->bgc_thread = GCToEEInterface::CreateBackgroundThread(gh->bgc_thread_stub, gh);
gh->bgc_thread_running = (gh->bgc_thread != NULL);

gh->bgc_thread_running = GCToEEInterface::CreateThread(gh->bgc_thread_stub, gh, true, L"Background GC");
return gh->bgc_thread_running;
}

Expand Down Expand Up @@ -26908,7 +26894,7 @@ void gc_heap::kill_gc_thread()
recursive_gc_sync::shutdown();
}

uint32_t gc_heap::bgc_thread_function()
void gc_heap::bgc_thread_function()
{
assert (background_gc_done_event.IsValid());
assert (bgc_start_event.IsValid());
Expand Down Expand Up @@ -27066,7 +27052,7 @@ uint32_t gc_heap::bgc_thread_function()
FireEtwGCTerminateConcurrentThread_V1(GetClrInstanceId());

dprintf (3, ("bgc_thread thread exiting"));
return 0;
return;
}

#endif //BACKGROUND_GC
Expand Down
13 changes: 7 additions & 6 deletions src/gc/gcenv.ee.standalone.inl
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,6 @@ inline void GCToEEInterface::GcEnumAllocContexts(enum_alloc_context_func* fn, vo
g_theGCToCLR->GcEnumAllocContexts(fn, param);
}

inline Thread* GCToEEInterface::CreateBackgroundThread(GCBackgroundThreadFunction threadStart, void* arg)
{
assert(g_theGCToCLR != nullptr);
return g_theGCToCLR->CreateBackgroundThread(threadStart, arg);
}

inline void GCToEEInterface::DiagGCStart(int gen, bool isInduced)
{
assert(g_theGCToCLR != nullptr);
Expand Down Expand Up @@ -258,4 +252,11 @@ inline bool GCToEEInterface::IsGCSpecialThread()
return g_theGCToCLR->IsGCSpecialThread();
}

inline bool GCToEEInterface::CreateThread(void (*threadStart)(void*), void* arg, bool is_special, const wchar_t* name)
{
assert(g_theGCToCLR != nullptr);
return g_theGCToCLR->CreateThread(threadStart, arg, is_special, name);
}


#endif // __GCTOENV_EE_STANDALONE_INL__
4 changes: 2 additions & 2 deletions src/gc/gcinterface.ee.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@ class IGCToCLR {
virtual
void GcEnumAllocContexts(enum_alloc_context_func* fn, void* param) = 0;

// Creates and returns a new background thread.
// Creates and returns a new thread.
virtual
Thread* CreateBackgroundThread(GCBackgroundThreadFunction threadStart, void* arg) = 0;
bool CreateThread(void (*threadStart)(void*), void* arg, bool is_special, const wchar_t* name) = 0;

// When a GC starts, gives the diagnostics code a chance to run.
virtual
Expand Down
4 changes: 2 additions & 2 deletions src/gc/gcpriv.h
Original file line number Diff line number Diff line change
Expand Up @@ -2671,11 +2671,11 @@ class gc_heap
PER_HEAP
void kill_gc_thread();
PER_HEAP
uint32_t bgc_thread_function();
void bgc_thread_function();
PER_HEAP_ISOLATED
void do_background_gc();
static
uint32_t __stdcall bgc_thread_stub (void* arg);
void bgc_thread_stub (void* arg);

#endif //BACKGROUND_GC

Expand Down
11 changes: 5 additions & 6 deletions src/gc/sample/gcenv.ee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,12 +231,6 @@ void GCToEEInterface::SyncBlockCachePromotionsGranted(int /*max_gen*/)
{
}

Thread* GCToEEInterface::CreateBackgroundThread(GCBackgroundThreadFunction threadStart, void* arg)
{
// TODO: Implement for background GC
return NULL;
}

void GCToEEInterface::DiagGCStart(int gen, bool isInduced)
{
}
Expand Down Expand Up @@ -330,3 +324,8 @@ MethodTable* GCToEEInterface::GetFreeObjectMethodTable()
{
return g_pFreeObjectMethodTable;
}

bool GCToEEInterface::CreateThread(void (*threadStart)(void*), void* arg, bool is_special, const wchar_t* name)
{
return nullptr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method returns bool...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack, you're right - this is left over from a previous refactor.

}
66 changes: 25 additions & 41 deletions src/gc/unix/gcenv.unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,31 @@ size_t GCToOSInterface::GetLargestOnDieCacheSize(bool trueSize)
return 0;
}

// Sets the calling thread's affinity to only run on the processor specified
// in the GCThreadAffinity structure.
// Parameters:
// affinity - The requested affinity for the calling thread. At most one processor
// can be provided.
// Return:
// true if setting the affinity was successful, false otherwise.
bool GCToOSInterface::SetThreadAffinity(GCThreadAffinity* affinity)
{
// [LOCALGC TODO] Thread affinity for unix
return false;
}

// Boosts the calling thread's thread priority to a level higher than the default
// for new threads.
// Parameters:
// None.
// Return:
// true if the priority boost was successful, false otherwise.
bool GCToOSInterface::BoostThreadPriority()
{
// [LOCALGC TODO] Thread priority for unix
return false;
}

/*++
Function:
GetFullAffinityMask
Expand Down Expand Up @@ -675,47 +700,6 @@ static void* GCThreadStub(void* param)
return NULL;
}

// Create a new thread for GC use
// Parameters:
// function - the function to be executed by the thread
// param - parameters of the thread
// affinity - processor affinity of the thread
// Return:
// true if it has succeeded, false if it has failed
bool GCToOSInterface::CreateThread(GCThreadFunction function, void* param, GCThreadAffinity* affinity)
{
std::unique_ptr<GCThreadStubParam> stubParam(new (std::nothrow) GCThreadStubParam());
if (!stubParam)
{
return false;
}

stubParam->GCThreadFunction = function;
stubParam->GCThreadParam = param;

pthread_attr_t attrs;

int st = pthread_attr_init(&attrs);
assert(st == 0);

// Create the thread as detached, that means not joinable
st = pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
assert(st == 0);

pthread_t threadId;
st = pthread_create(&threadId, &attrs, GCThreadStub, stubParam.get());

if (st == 0)
{
stubParam.release();
}

int st2 = pthread_attr_destroy(&attrs);
assert(st2 == 0);

return (st == 0);
}

// Gets the total number of processors on the machine, not taking
// into account current process affinity.
// Return:
Expand Down
Loading