173 lines
5.4 KiB
C++
173 lines
5.4 KiB
C++
// Copyright 2019 The Marl Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#ifndef marl_thread_h
|
|
#define marl_thread_h
|
|
|
|
#include "containers.h"
|
|
#include "export.h"
|
|
|
|
#include <functional>
|
|
|
|
namespace marl {
|
|
|
|
// Thread provides an OS abstraction for threads of execution.
|
|
class Thread {
|
|
public:
|
|
using Func = std::function<void()>;
|
|
|
|
// Core identifies a logical processor unit.
|
|
// How a core is identified varies by platform.
|
|
struct Core {
|
|
struct Windows {
|
|
uint8_t group; // Group number
|
|
uint8_t index; // Core within the processor group
|
|
};
|
|
struct Pthread {
|
|
uint16_t index; // Core number
|
|
};
|
|
union {
|
|
Windows windows;
|
|
Pthread pthread;
|
|
};
|
|
|
|
// Comparison functions
|
|
MARL_NO_EXPORT inline bool operator==(Core) const;
|
|
MARL_NO_EXPORT inline bool operator<(Core) const;
|
|
};
|
|
|
|
// Affinity holds the affinity mask for a thread - a description of what cores
|
|
// the thread is allowed to run on.
|
|
struct Affinity {
|
|
// supported is true if marl supports controlling thread affinity for this
|
|
// platform.
|
|
#if defined(_WIN32) || \
|
|
(defined(__linux__) && !defined(__ANDROID__) && !defined(__BIONIC__)) || \
|
|
defined(__FreeBSD__)
|
|
static constexpr bool supported = true;
|
|
#else
|
|
static constexpr bool supported = false;
|
|
#endif
|
|
|
|
// Policy is an interface that provides a get() method for returning an
|
|
// Affinity for the given thread by id.
|
|
class Policy {
|
|
public:
|
|
virtual ~Policy() {}
|
|
|
|
// anyOf() returns a Policy that returns an Affinity for a number of
|
|
// available cores in affinity.
|
|
//
|
|
// Windows requires that each thread is only associated with a
|
|
// single affinity group, so the Policy's returned affinity will contain
|
|
// cores all from the same group.
|
|
MARL_EXPORT static std::shared_ptr<Policy> anyOf(
|
|
Affinity&& affinity,
|
|
Allocator* allocator = Allocator::Default);
|
|
|
|
// oneOf() returns a Policy that returns an affinity with a single enabled
|
|
// core from affinity. The single enabled core in the Policy's returned
|
|
// affinity is:
|
|
// affinity[threadId % affinity.count()]
|
|
MARL_EXPORT static std::shared_ptr<Policy> oneOf(
|
|
Affinity&& affinity,
|
|
Allocator* allocator = Allocator::Default);
|
|
|
|
// get() returns the thread Affinity for the given thread by id.
|
|
MARL_EXPORT virtual Affinity get(uint32_t threadId,
|
|
Allocator* allocator) const = 0;
|
|
};
|
|
|
|
MARL_EXPORT Affinity(Allocator*);
|
|
|
|
MARL_EXPORT Affinity(Affinity&&);
|
|
|
|
MARL_EXPORT Affinity& operator=(Affinity&&);
|
|
|
|
MARL_EXPORT Affinity(const Affinity&, Allocator* allocator);
|
|
|
|
// all() returns an Affinity with all the cores available to the process.
|
|
MARL_EXPORT static Affinity all(Allocator* allocator = Allocator::Default);
|
|
|
|
MARL_EXPORT Affinity(std::initializer_list<Core>, Allocator* allocator);
|
|
|
|
MARL_EXPORT Affinity(const containers::vector<Core, 32>&,
|
|
Allocator* allocator);
|
|
|
|
// count() returns the number of enabled cores in the affinity.
|
|
MARL_EXPORT size_t count() const;
|
|
|
|
// operator[] returns the i'th enabled core from this affinity.
|
|
MARL_EXPORT Core operator[](size_t index) const;
|
|
|
|
// add() adds the cores from the given affinity to this affinity.
|
|
// This affinity is returned to allow for fluent calls.
|
|
MARL_EXPORT Affinity& add(const Affinity&);
|
|
|
|
// remove() removes the cores from the given affinity from this affinity.
|
|
// This affinity is returned to allow for fluent calls.
|
|
MARL_EXPORT Affinity& remove(const Affinity&);
|
|
|
|
private:
|
|
Affinity(const Affinity&) = delete;
|
|
|
|
containers::vector<Core, 32> cores;
|
|
};
|
|
|
|
MARL_EXPORT Thread() = default;
|
|
|
|
MARL_EXPORT Thread(Thread&&);
|
|
|
|
MARL_EXPORT Thread& operator=(Thread&&);
|
|
|
|
// Start a new thread using the given affinity that calls func.
|
|
MARL_EXPORT Thread(Affinity&& affinity, Func&& func);
|
|
|
|
MARL_EXPORT ~Thread();
|
|
|
|
// join() blocks until the thread completes.
|
|
MARL_EXPORT void join();
|
|
|
|
// setName() sets the name of the currently executing thread for displaying
|
|
// in a debugger.
|
|
MARL_EXPORT static void setName(const char* fmt, ...);
|
|
|
|
// numLogicalCPUs() returns the number of available logical CPU cores for
|
|
// the system.
|
|
MARL_EXPORT static unsigned int numLogicalCPUs();
|
|
|
|
private:
|
|
Thread(const Thread&) = delete;
|
|
Thread& operator=(const Thread&) = delete;
|
|
|
|
class Impl;
|
|
Impl* impl = nullptr;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Thread::Core
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Comparison functions
|
|
bool Thread::Core::operator==(Core other) const {
|
|
return pthread.index == other.pthread.index;
|
|
}
|
|
|
|
bool Thread::Core::operator<(Core other) const {
|
|
return pthread.index < other.pthread.index;
|
|
}
|
|
|
|
} // namespace marl
|
|
|
|
#endif // marl_thread_h
|