[m-rev.] for review: Fix use of Linux CPU affinity API.
Peter Wang
novalazy at gmail.com
Wed May 16 17:18:20 AEST 2018
For review by Paul or anyone.
----
The main fix is to retry the sched_getaffinity() call in
MR_reset_available_cpus(). If that call failed because we provided a
cpuset that is too small for the kernel, MR_reset_available_cpus() would
set MR_available_cpus to NULL but leave MR_cpuset_size non-zero,
leading to a null pointer dereference soon after.
runtime/mercury_context.c:
runtime/mercury_context.h:
Use a macro MR_HAVE_LINUX_CPU_AFFINITY_API if we have all the pieces
we need for that API.
Rename MR_num_processors to MR_num_processors_detected for clarity.
Add a global variable MR_cpuset_num_cpus to record the size of the
cpuset that we allocated.
Change MR_cpuset_size to size_t to match the type in the underlying
interface.
Rename MR_available_cpus to MR_cpuset_available to clarify the
relationship with MR_cpuset_size and MR_cpuset_num_cpus.
In MR_reset_available_cpus(), retry sched_getaffinity() if it fails
with EINVAL. It may fail because the kernel uses a larger CPU
affinity mask than the cpuset we provided; then we must retry the
call with a larger cpuset.
Ensure MR_reset_available_cpus() does not leave MR_cpuset_*
variables in an inconsistent state.
Make MR_detect_num_processors() set MR_num_processors to 1 if the
MR_cpuset_available set is somehow empty after
MR_reset_available_cpus(). It should not happen, but the program
should be able to continue anyway.
In MR_pin_thread_no_locking(), loop over the entire
MR_cpuset_available set to find a target CPU to pin to.
The CPUs available to the thread are not necessarily numbered
consecutively from the initial CPU onwards mod MR_num_processors.
Fix cpuset allocation in MR_do_pin_thread to not assume that CPUs
are numbered from 0 to MR_num_processors-1. Fix a memory leak.
Clean up MR_current_cpu().
Prevent a null pointer dereference in the hwloc path:
hwloc_get_pu_obj_by_os_index always returns NULL on my system.
Change some types from 'unsigned' to 'int' to match underlying APIs.
library/thread.m:
Conform to variable renaming.
---
library/thread.m | 2 +-
runtime/mercury_context.c | 277 ++++++++++++++++++++++++--------------
runtime/mercury_context.h | 10 +-
3 files changed, 180 insertions(+), 109 deletions(-)
diff --git a/library/thread.m b/library/thread.m
index 0c3a0b2c4..0e11177ed 100644
--- a/library/thread.m
+++ b/library/thread.m
@@ -808,21 +808,21 @@ num_processors(MaybeProcs, !IO) :-
).
:- pred num_processors(int::out, bool::out, io::di, io::uo) is det.
:- pragma foreign_proc("C",
num_processors(Procs::out, Success::out, _IO0::di, _IO::uo),
[promise_pure, thread_safe, will_not_call_mercury,
will_not_throw_exception, tabled_for_io],
"
#ifdef MR_THREAD_SAFE
- Procs = MR_num_processors;
+ Procs = MR_num_processors_detected;
Success = MR_YES;
#else
Procs = 1;
Success = MR_YES;
#endif
").
:- pragma foreign_proc("Java",
num_processors(Procs::out, Success::out, _IO0::di, _IO::uo),
[promise_pure, thread_safe, will_not_call_mercury,
diff --git a/runtime/mercury_context.c b/runtime/mercury_context.c
index a050c865b..cf573380c 100644
--- a/runtime/mercury_context.c
+++ b/runtime/mercury_context.c
@@ -1,14 +1,14 @@
// vim: ts=4 sw=4 expandtab ft=c
// Copyright (C) 1995-2007, 2009-2011 The University of Melbourne.
-// Copyright (C) 2014, 2016 The Mercury team.
+// Copyright (C) 2014, 2016-2018 The Mercury team.
// This file may only be copied under the terms of the GNU Library General
// Public License - see the file COPYING.LIB in the Mercury distribution.
// mercury_context.c - handles multithreading stuff.
/*
INIT mercury_sys_init_scheduler_wrapper
ENDINIT
*/
@@ -33,47 +33,47 @@ ENDINIT
#include <sys/types.h> // for fd_set
#include <sys/time.h> // for struct timeval
#ifdef MR_HAVE_UNISTD_H
#include <unistd.h> // for select() on OS X
#endif
#endif
#ifdef MR_PROFILE_PARALLEL_EXECUTION_SUPPORT
#include <math.h> // for sqrt and pow
#endif
-#ifdef MR_HAVE_SCHED_H
- #include <sched.h>
+#if defined(MR_THREAD_SAFE) && defined(MR_HAVE_HWLOC)
+ #include <hwloc.h>
+#endif
- // These macros first appeared in glibc 2.7.
- #if defined(CPU_ALLOC) && defined(CPU_ALLOC_SIZE) && defined(CPU_FREE) && \
- defined(CPU_ZERO_S) && defined(CPU_SET_S) && defined(CPU_CLR_S) && \
- defined(CPU_ISSET_S) && defined(CPU_COUNT_S)
- #define MR_HAVE_CPU_SET_MACROS 1
- #endif
+// The CPU_* macros first appeared in glibc 2.7.
+#if defined(MR_HAVE_SCHED_H) && \
+ defined(MR_HAVE_SCHED_GETAFFINITY) && \
+ defined(MR_HAVE_SCHED_SETAFFINITY) && \
+ defined(CPU_ALLOC) && defined(CPU_ALLOC_SIZE) && defined(CPU_FREE) && \
+ defined(CPU_ZERO_S) && defined(CPU_SET_S) && defined(CPU_CLR_S) && \
+ defined(CPU_ISSET_S) && defined(CPU_COUNT_S)
+ #include <sched.h>
+ #define MR_HAVE_LINUX_CPU_AFFINITY_API 1
#endif
#ifdef MR_MINGW
#include <sys/time.h> // for gettimeofday()
#endif
#ifdef MR_WIN32
#include <sys/timeb.h> // for _ftime()
#endif
#ifdef MR_WIN32_GETSYSTEMINFO
#include "mercury_windows.h"
#endif
-#if defined(MR_THREAD_SAFE) && defined(MR_HAVE_HWLOC)
- #include <hwloc.h>
-#endif
-
#include "mercury_memory_handlers.h"
#include "mercury_context.h"
#include "mercury_engine.h" // for `MR_memdebug'
#include "mercury_threadscope.h" // for data types and posting events
#include "mercury_reg_workarounds.h" // for `MR_fd*' stuff
#ifdef MR_PROFILE_PARALLEL_EXECUTION_SUPPORT
#define MR_PROFILE_PARALLEL_EXECUTION_FILENAME "parallel_execution_profile.txt"
#endif
@@ -201,30 +201,40 @@ static MR_Integer MR_profile_parallel_contexts_created_for_sparks = 0;
// list lock.
static MR_Integer MR_profile_parallel_small_context_reused = 0;
static MR_Integer MR_profile_parallel_regular_context_reused = 0;
static MR_Integer MR_profile_parallel_small_context_kept = 0;
static MR_Integer MR_profile_parallel_regular_context_kept = 0;
#endif // ! MR_HIGHLEVEL_CODE
#endif // MR_PROFILE_PARALLEL_EXECUTION_SUPPORT
#ifdef MR_THREAD_SAFE
-// Detect number of processors.
-unsigned MR_num_processors;
+// The detected number of processors available to this process.
+unsigned MR_num_processors_detected;
+
#if defined(MR_HAVE_HWLOC)
static hwloc_topology_t MR_hw_topology;
static hwloc_cpuset_t MR_hw_available_pus = NULL;
-#elif defined(MR_HAVE_SCHED_SETAFFINITY)
- static cpu_set_t *MR_available_cpus;
- // The number of CPUs that MR_available_cpus can refer to.
- static unsigned MR_cpuset_size = 0;
+#elif defined(MR_HAVE_LINUX_CPU_AFFINITY_API)
+ // The number of CPUs that can be represented by MR_cpuset_available.
+ static int MR_cpuset_num_cpus = 0;
+
+ // The size of MR_cpuset_available in bytes, given by
+ // CPU_ALLOC_SIZE(MR_cpuset_num_cpus).
+ static size_t MR_cpuset_size = 0;
+
+ // A cpuset of MR_cpuset_size bytes, able to represent processors in the
+ // range [0, MR_cpuset_num_cpus).
+ // NOTE: the processors available to a process are NOT necessarily
+ // numbered from 0 to MR_num_processors_detected-1.
+ static cpu_set_t *MR_cpuset_available;
#endif
// Local variables for thread pinning.
#if defined(MR_LL_PARALLEL_CONJ) && defined(MR_HAVE_THREAD_PINNING)
MR_bool MR_thread_pinning = MR_FALSE;
static MercuryLock MR_thread_pinning_lock;
static unsigned MR_num_threads_left_to_pin;
MR_Unsigned MR_primordial_thread_cpu;
#endif
@@ -352,21 +362,21 @@ MR_init_context_stuff(void)
MR_sem_init(&shutdown_ws_semaphore, 0);
#endif
pthread_mutex_init(&MR_STM_lock, MR_MUTEX_ATTR);
#ifdef MR_HIGHLEVEL_CODE
MR_KEY_CREATE(&MR_backjump_handler_key, NULL);
MR_KEY_CREATE(&MR_backjump_next_choice_id_key, (void *)0);
#endif
MR_detect_num_processors();
- assert(MR_num_processors > 0);
+ assert(MR_num_processors_detected > 0);
#ifdef MR_LL_PARALLEL_CONJ
MR_setup_num_threads();
assert(MR_num_ws_engines > 0);
#if defined(MR_HAVE_THREAD_PINNING)
MR_setup_thread_pinning();
#endif
MR_granularity_wsdeque_length =
@@ -416,154 +426,204 @@ MR_reset_available_cpus(void)
// libhwloc_1.0-1 (Debian) hwloc reported that all cpus on the system are
// available, it didn't exclude cpus not in the processor's cpuset(7).
if (MR_hw_available_pus == NULL) {
MR_hw_available_pus = hwloc_bitmap_alloc();
}
hwloc_bitmap_and(MR_hw_available_pus, inherited_binding,
hwloc_topology_get_allowed_cpuset(MR_hw_topology));
hwloc_bitmap_free(inherited_binding);
- #elif defined(MR_HAVE_SCHED_GETAFFINITY) && defined(MR_HAVE_CPU_SET_MACROS)
- unsigned cpuset_size;
- unsigned num_processors;
-
- if (MR_cpuset_size) {
- cpuset_size = MR_cpuset_size;
- num_processors = MR_num_processors;
+ #elif defined(MR_HAVE_LINUX_CPU_AFFINITY_API)
+ int num_cpus;
+ size_t cpuset_size = 0;
+ cpu_set_t *cpuset = NULL;
+
+ if (MR_cpuset_num_cpus > 0) {
+ // Start with the same cpuset size that we determined in a previous
+ // call to this function.
+ num_cpus = MR_cpuset_num_cpus;
} else {
#if defined(MR_HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
- num_processors = sysconf(_SC_NPROCESSORS_ONLN);
+ num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
#else
// Make the CPU set at least 32 processors wide.
-
- num_processors = 32;
+ // The minimum cpuset size on 32-bit architectures is 32-bits.
+ num_cpus = 32;
#endif
- cpuset_size = CPU_ALLOC_SIZE(num_processors);
- MR_cpuset_size = cpuset_size;
}
- if (MR_available_cpus == NULL) {
- MR_available_cpus = CPU_ALLOC(num_processors);
+ // Free an existing cpuset if we have been here before.
+ if (MR_cpuset_available != NULL) {
+ CPU_FREE(MR_cpuset_available);
+ MR_cpuset_available = NULL;
+ MR_cpuset_size = 0;
+ MR_cpuset_num_cpus = 0;
}
- if (-1 == sched_getaffinity(0, cpuset_size, MR_available_cpus)) {
+ // This huge limit is just to prevent the possibility of looping forever.
+ // In most cases we will succeed on the first attempt.
+ while (num_cpus <= 0x100000) {
+ int err;
+
+ cpuset_size = CPU_ALLOC_SIZE(num_cpus);
+ cpuset = CPU_ALLOC(num_cpus);
+ if (cpuset == NULL) {
+ break;
+ }
+ if (sched_getaffinity(0, cpuset_size, cpuset) == 0) {
+ break;
+ }
+ err = errno;
+ CPU_FREE(cpuset);
+ cpuset = NULL;
+ if (err != EINVAL) {
+ break;
+ }
+ // sched_getaffinity() can return EINVAL if the kernel uses larger CPU
+ // affinity masks than the one we provided. Then we must retry with a
+ // larger mask size.
+ if (num_cpus < 512) {
+ num_cpus = 512;
+ } else {
+ num_cpus *= 2;
+ }
+ }
+
+ if (cpuset != NULL) {
+ MR_cpuset_num_cpus = num_cpus;
+ MR_cpuset_size = cpuset_size;
+ MR_cpuset_available = cpuset;
+ } else {
MR_perror("Couldn't get CPU affinity");
#if defined(MR_LL_PARALLEL_CONJ) && defined(MR_HAVE_THREAD_PINNING)
MR_thread_pinning = MR_FALSE;
#endif
- CPU_FREE(MR_available_cpus);
- MR_available_cpus = NULL;
}
#endif
}
static void
MR_detect_num_processors(void)
{
#ifdef MR_HAVE_HWLOC
if (-1 == hwloc_topology_init(&MR_hw_topology)) {
MR_fatal_error("Error allocating libhwloc topology object");
}
if (-1 == hwloc_topology_load(MR_hw_topology)) {
MR_fatal_error("Error detecting hardware topology (hwloc)");
}
#endif
// Setup num processors.
MR_reset_available_cpus();
- #ifdef MR_HAVE_HWLOC
- MR_num_processors = hwloc_bitmap_weight(MR_hw_available_pus);
- #elif defined(MR_HAVE_SCHED_GETAFFINITY) && defined(MR_HAVE_CPU_SET_MACROS)
- MR_num_processors = CPU_COUNT_S(MR_cpuset_size, MR_available_cpus);
+ #if defined(MR_HAVE_HWLOC)
+ MR_num_processors_detected = hwloc_bitmap_weight(MR_hw_available_pus);
+ #elif defined(MR_HAVE_LINUX_CPU_AFFINITY_API)
+ MR_num_processors_detected =
+ CPU_COUNT_S(MR_cpuset_size, MR_cpuset_available);
+ if (MR_num_processors_detected == 0) {
+ // Carry on even if the MR_cpuset_available is somehow empty.
+ MR_num_processors_detected = 1;
+ }
#elif defined(MR_WIN32_GETSYSTEMINFO)
{
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
- MR_num_processors = sysinfo.dwNumberOfProcessors;
+ MR_num_processors_detected = sysinfo.dwNumberOfProcessors;
}
#elif defined(MR_HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
- MR_num_processors = sysconf(_SC_NPROCESSORS_ONLN);
+ MR_num_processors_detected = sysconf(_SC_NPROCESSORS_ONLN);
#else
- #warning "Cannot detect MR_num_processors"
- MR_num_processors = 1;
+ #warning "Cannot detect MR_num_processors_detected"
+ MR_num_processors_detected = 1;
#endif
}
#ifdef MR_LL_PARALLEL_CONJ
static void
MR_setup_num_threads(void)
{
// If MR_num_threads is unset, configure it to match number of processors
// on the system. If we do this, then we prepare to set processor
// affinities later on.
if (MR_num_ws_engines == 0) {
- MR_num_ws_engines = MR_num_processors;
+ MR_num_ws_engines = MR_num_processors_detected;
}
#ifdef MR_DEBUG_THREADS
if (MR_debug_threads) {
fprintf(stderr, "Detected %d processors, will use %d threads\n",
- MR_num_processors, MR_num_ws_engines);
+ MR_num_processors_detected, MR_num_ws_engines);
}
#endif
}
#endif // MR_LL_PARALLEL_CONJ
#endif // MR_THREAD_SAFE
// Thread pinning.
#if defined(MR_HAVE_THREAD_PINNING) && defined(MR_LL_PARALLEL_CONJ)
-// Pin the primordial thread first to the CPU it is currently using
-// (if support is available for thread pinning).
-static unsigned
+static int
MR_pin_thread_no_locking(void)
{
- unsigned cpu;
- unsigned i = 0;
+ int initial_cpu;
+ int max;
+ int i;
- cpu = MR_current_cpu();
-#ifdef MR_DEBUG_THREAD_PINNING
- fprintf(stderr, "Currently running on cpu %d\n", cpu);
-#endif
+ initial_cpu = MR_current_cpu();
+ #ifdef MR_DEBUG_THREAD_PINNING
+ fprintf(stderr, "Currently running on cpu %d\n", initial_cpu);
+ #endif
- for (i = 0; (i < MR_num_processors) && MR_thread_pinning; i++) {
- if (MR_do_pin_thread((cpu + i) % MR_num_processors)) {
-#ifdef MR_DEBUG_THREAD_PINNING
- fprintf(stderr, "Pinned to cpu %d\n", (cpu + i) % MR_num_processors);
- fprintf(stderr, "Now running on cpu %d\n", MR_current_cpu());
-#endif
+ #if defined(MR_HAVE_HWLOC)
+ max = MR_num_processors_detected;
+ #elif defined(MR_HAVE_LINUX_CPU_AFFINITY_API)
+ // CPUs available to this process do not have to be numbered consecutively.
+ max = MR_cpuset_num_cpus;
+ #else
+ #error Should be unreachable
+ #endif
+
+ for (i = 0; (i < max) && MR_thread_pinning; i++) {
+ int target_cpu = (initial_cpu + i) % max;
+
+ if (MR_do_pin_thread(target_cpu)) {
+ #ifdef MR_DEBUG_THREAD_PINNING
+ fprintf(stderr, "Pinned to cpu %d, running on cpu %d\n",
+ target_cpu, MR_current_cpu());
+ #endif
MR_num_threads_left_to_pin--;
- MR_make_cpu_unavailable((cpu + i) % MR_num_processors);
- return (cpu + i) % MR_num_processors;
+ MR_make_cpu_unavailable(target_cpu);
+ return target_cpu;
}
+
if (!MR_thread_pinning) {
// If MR_thread_pinning becomes false then an error prevented us
// from pinning the thread.
// When we fail to pin a thread but MR_thread_pinning remains true
// it means that CPU has already had a thread pinned to it.
-
fprintf(stderr, "Couldn't pin Mercury engine to processor");
break;
}
}
- return cpu;
+ return initial_cpu;
}
-unsigned
+int
MR_pin_thread(void)
{
- unsigned cpu;
+ int cpu;
MR_LOCK(&MR_thread_pinning_lock, "MR_pin_thread");
cpu = MR_pin_thread_no_locking();
MR_UNLOCK(&MR_thread_pinning_lock, "MR_pin_thread");
return cpu;
}
void
MR_pin_primordial_thread(void)
@@ -577,57 +637,56 @@ MR_pin_primordial_thread(void)
static void MR_setup_thread_pinning(void)
{
MR_num_threads_left_to_pin = MR_num_ws_engines;
pthread_mutex_init(&MR_thread_pinning_lock, MR_MUTEX_ATTR);
// Comment this back in to enable thread pinning by default
// if we autodetected the number of CPUs without error.
#if 0
- if (MR_num_processors > 1) {
+ if (MR_num_processors_detected > 1) {
MR_thread_pinning = MR_TRUE;
}
#endif
}
// Determine which CPU this thread is currently running on.
static int MR_current_cpu(void)
{
-#if defined(MR_HAVE_SCHED_GETCPU)
- int os_cpu;
+ int os_cpu;
+
#if defined(MR_HAVE_HWLOC)
hwloc_obj_t pu;
+ pu = hwloc_get_pu_obj_by_os_index(MR_hw_topology, os_cpu);
+ if (pu != NULL) {
+ os_cpu = pu->logical_index;
+ } else {
+ // XXX Quick hack to prevent crashes only.
+ os_cpu = -1;
+ }
+#elif defined(MR_HAVE_SCHED_GETCPU)
+ os_cpu = sched_getcpu();
+#else
+ os_cpu = 0;
#endif
- os_cpu = sched_getcpu();
- if (-1 == os_cpu) {
+ if (os_cpu < 0) {
os_cpu = 0;
-
if (MR_thread_pinning) {
MR_perror("Warning: unable to determine the current CPU for "
"this thread: ");
}
}
-#if defined(MR_HAVE_HWLOC)
- pu = hwloc_get_pu_obj_by_os_index(MR_hw_topology, os_cpu);
- return pu->logical_index;
-#else
return os_cpu;
-#endif
-
-#else // ! MR_HAVE_SCHED_GETCPU
- // We have no idea!
- return 0;
-#endif
}
static MR_bool
MR_do_pin_thread(int cpu)
{
// Make sure that we are allowed to bind to this CPU.
#if defined(MR_HAVE_HWLOC)
hwloc_obj_t pu;
@@ -636,70 +695,84 @@ MR_do_pin_thread(int cpu)
// available_pus set so that we can oversubscribe CPUs but still
// attempt to balance load.
MR_reset_available_cpus();
}
pu = hwloc_get_obj_by_type(MR_hw_topology, HWLOC_OBJ_PU, cpu);
if (!hwloc_bitmap_intersects(MR_hw_available_pus, pu->cpuset)) {
return MR_FALSE;
}
-#elif defined(MR_HAVE_SCHED_SETAFFINITY) && defined(MR_HAVE_CPU_SET_MACROS)
- if (CPU_COUNT_S(MR_cpuset_size, MR_available_cpus) == 0) {
+#elif defined(MR_HAVE_LINUX_CPU_AFFINITY_API)
+ if (CPU_COUNT_S(MR_cpuset_size, MR_cpuset_available) == 0) {
// As above, reset the available cpus.
MR_reset_available_cpus();
}
- if (!CPU_ISSET_S(cpu, MR_cpuset_size, MR_available_cpus)) {
+ if (!CPU_ISSET_S(cpu, MR_cpuset_size, MR_cpuset_available)) {
return MR_FALSE;
}
#endif
#if defined(MR_HAVE_HWLOC)
errno = hwloc_set_cpubind(MR_hw_topology, pu->cpuset,
HWLOC_CPUBIND_THREAD);
if (errno != 0) {
MR_perror("Warning: Couldn't set CPU affinity: ");
MR_thread_pinning = MR_FALSE;
return MR_FALSE;
}
-#elif defined(MR_HAVE_SCHED_SETAFFINITY) && defined(MR_HAVE_CPU_SET_MACROS)
- cpu_set_t *cpus;
-
- cpus = CPU_ALLOC(MR_num_processors);
-
- CPU_ZERO_S(MR_cpuset_size, cpus);
- CPU_SET_S(cpu, MR_cpuset_size, cpus);
- if (sched_setaffinity(0, MR_cpuset_size, cpus) == -1) {
- MR_perror("Warning: Couldn't set CPU affinity: ");
- // If this failed once, it will probably fail again, so we disable it.
-
- MR_thread_pinning = MR_FALSE;
- return MR_FALSE;
+#elif defined(MR_HAVE_LINUX_CPU_AFFINITY_API)
+ size_t cpuset_size;
+ cpu_set_t *cpuset;
+ MR_bool success;
+
+ // The man page for sched_setaffinity() says that Linux 2.6.9 and earlier
+ // may return EINVAL if given a cpuset size smaller than size of the
+ // affinity mask used by the kernel, so we allocate a cpuset large enough
+ // for MR_cpuset_num_cpus, not just cpu.
+ cpuset_size = CPU_ALLOC_SIZE(MR_cpuset_num_cpus);
+ cpuset = CPU_ALLOC(MR_cpuset_num_cpus);
+ if (cpuset != NULL) {
+ CPU_ZERO_S(cpuset_size, cpuset);
+ CPU_SET_S(cpu, cpuset_size, cpuset);
+ if (sched_setaffinity(0, cpuset_size, cpuset) == 0) {
+ success = MR_TRUE;
+ } else {
+ MR_perror("Warning: Couldn't set CPU affinity: ");
+ // If this failed once, it will probably fail again.
+ // Disable thread pinning from now on.
+ MR_thread_pinning = MR_FALSE;
+ success = MR_FALSE;
+ }
+ CPU_FREE(cpuset);
+ } else {
+ success = MR_FALSE;
}
+ return success;
#endif
return MR_TRUE;
}
#if defined(MR_HAVE_HWLOC)
static MR_bool MR_make_pu_unavailable(const struct hwloc_obj *pu);
#endif
static void MR_make_cpu_unavailable(int cpu)
{
#if defined(MR_HAVE_HWLOC)
hwloc_obj_t pu;
pu = hwloc_get_obj_by_type(MR_hw_topology, HWLOC_OBJ_PU, cpu);
MR_make_pu_unavailable(pu);
-#elif defined(MR_HAVE_SCHED_SETAFFINITY) && defined(MR_HAVE_CPU_SET_MACROS)
- CPU_CLR_S(cpu, MR_cpuset_size, MR_available_cpus);
+#elif defined(MR_HAVE_LINUX_CPU_AFFINITY_API)
+ CPU_CLR_S(cpu, MR_cpuset_size, MR_cpuset_available);
#endif
}
#if defined(MR_HAVE_HWLOC)
static MR_bool MR_make_pu_unavailable(const struct hwloc_obj *pu)
{
hwloc_obj_t core;
static int siblings_to_make_unavailable;
int i;
diff --git a/runtime/mercury_context.h b/runtime/mercury_context.h
index e15682a69..11d7d880c 100644
--- a/runtime/mercury_context.h
+++ b/runtime/mercury_context.h
@@ -369,22 +369,22 @@ extern MR_Context *MR_runqueue_tail;
#endif
#ifdef MR_PROFILE_PARALLEL_EXECUTION_SUPPORT
extern MR_bool MR_profile_parallel_execution;
// XXX: This is currently unused, we plan to use it in the future. -pbone
extern MR_Stats MR_profile_parallel_executed_local_sparks;
#endif
#ifdef MR_THREAD_SAFE
-// The number of processors available.
-extern unsigned MR_num_processors;
+// The number of processors detected.
+extern unsigned MR_num_processors_detected;
#endif
// As well as the runqueue, we maintain a linked list of contexts
// and associated file descriptors that are suspended blocked for
// reads/writes/exceptions. When the runqueue becomes empty, if
// this list is not empty then we call select and block until one
// or more of the file descriptors become ready for I/O, then
// wake the appropriate context.
// In addition, we should periodically check to see if the list of blocked
// contexts is non-empty and if so, poll to wake any contexts that
@@ -465,24 +465,22 @@ extern void MR_init_context_stuff(void);
// MR_pin_primordial_thread() is a special case for the primordial thread.
// It should only be executed once, and only by the primordial thread _before_
// the other threads are started.
//
// Both functions return the CPU number that the thread is pinned to or would
// be pinned to if pinning was both enabled and supported. That is a valid
// value is always returned even if the thread is not actually pinned.
#if defined(MR_LL_PARALLEL_CONJ)
#if defined(MR_HAVE_THREAD_PINNING)
-extern void
-MR_pin_primordial_thread(void);
-extern unsigned
-MR_pin_thread(void);
+extern void MR_pin_primordial_thread(void);
+extern int MR_pin_thread(void);
// The CPU that the primordial thread is running on.
extern MR_Unsigned MR_primordial_thread_cpu;
#endif
// Shutdown all the work-stealing engines.
// (Exclusive engines shut down by themselves.)
extern void
--
2.17.0
More information about the reviews
mailing list