blob: e4061ebef9dfbc4287c258ac4c4754a3a41cf410 [file] [log] [blame]
/* Wrappers for C++ threading
Copyright (C) 2025 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef GDBSUPPORT_CXX_THREAD_H
#define GDBSUPPORT_CXX_THREAD_H
/* This header implements shims for the parts of the C++ threading
library that are needed by gdb.
The reason this exists is that some versions of libstdc++ do not
supply a working C++ thread implementation. In particular this was
true for several versions of the Windows compiler. See
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93687.
For systems where this works, this header just supplies aliases of
the standard functionality, in the "gdb" namespace. For example,
"gdb::mutex" is an alias for "std::mutex".
For non-working ports, shims are provided. These are just the
subset needed by gdb, and they generally do nothing, or as little
as possible. In particular they all simply assume single-threaded
operation. */
#if CXX_STD_THREAD
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
namespace gdb
{
using condition_variable = std::condition_variable;
using cv_status = std::cv_status;
using future_status = std::future_status;
using mutex = std::mutex;
using recursive_mutex = std::recursive_mutex;
using thread = std::thread;
namespace this_thread = std::this_thread;
template<typename T>
using lock_guard = std::lock_guard<T>;
template<typename T>
using unique_lock = std::unique_lock<T>;
template<typename T>
using future = std::future<T>;
} /* namespace gdb*/
#else
#include <chrono>
namespace gdb
{
/* A do-nothing replacement for std::mutex. */
struct mutex
{
mutex () = default;
DISABLE_COPY_AND_ASSIGN (mutex);
void lock ()
{
}
void unlock ()
{
}
};
/* A do-nothing replacement for std::recursive_mutex. */
struct recursive_mutex
{
recursive_mutex () = default;
DISABLE_COPY_AND_ASSIGN (recursive_mutex);
void lock ()
{
}
void unlock ()
{
}
};
/* A do-nothing replacement for std::lock_guard. */
template<typename T>
struct lock_guard
{
explicit lock_guard (T &m)
{
}
DISABLE_COPY_AND_ASSIGN (lock_guard);
};
/* A do-nothing replacement for std::unique_lock. */
template<typename T>
struct unique_lock
{
explicit unique_lock (T &m)
{
}
DISABLE_COPY_AND_ASSIGN (unique_lock);
};
/* A compatibility enum for std::cv_status. */
enum class cv_status
{
no_timeout,
timeout,
};
/* A do-nothing replacement for std::condition_variable. */
struct condition_variable
{
condition_variable () = default;
DISABLE_COPY_AND_ASSIGN (condition_variable);
void notify_one () noexcept
{
}
void wait (unique_lock<mutex> &lock)
{
}
template<class Rep, class Period>
cv_status wait_for (unique_lock<mutex> &lock,
const std::chrono::duration<Rep, Period> &rel_time)
{
return cv_status::no_timeout;
}
};
/* A compatibility enum for std::future_status. This is just the
subset needed by gdb. */
enum class future_status
{
ready,
timeout,
};
/* A compatibility implementation of std::future. */
template<typename T>
class future
{
public:
explicit future (T value)
: m_value (std::move (value))
{
}
future () = default;
future (future &&other) = default;
future (const future &other) = delete;
future &operator= (future &&other) = default;
future &operator= (const future &other) = delete;
void wait () const { }
template<class Rep, class Period>
future_status wait_for (const std::chrono::duration<Rep,Period> &duration)
const
{
return future_status::ready;
}
T get () { return std::move (m_value); }
private:
T m_value;
};
/* A specialization for void. */
template<>
class future<void>
{
public:
void wait () const { }
template<class Rep, class Period>
future_status wait_for (const std::chrono::duration<Rep,Period> &duration)
const
{
return future_status::ready;
}
void get () { }
};
/* Rather than try to write a gdb::thread class, we just use a
namespace since only the 'id' type is needed. Code manipulating
actual std::thread objects has to be wrapped in a check anyway. */
namespace thread
{
/* Replacement for std::thread::id. */
using id = int;
}
/* Replacement for std::this_thread. */
namespace this_thread
{
static inline thread::id
get_id ()
{
return 0;
}
}
} /* namespace gdb */
#endif /* CXX_STD_THREAD */
#endif /* GDBSUPPORT_CXX_THREAD_H */