Bug 1900287: Grudgingly refactor GetUiaClientPidsWin11 into a class to make MinGW happy. r=nlapre

In order to keep all of the tragic implementation detail for this function in a single class, I originally put the structs and the thread proc inside the function.
The thread proc was implemented as a lambda which implicitly converts to a function pointer.
Unfortunately, it seems MinGW can't implicitly convert this lambda to a function with the stdcall calling convention.
This is why we can't have nice things.
To deal with this, refactor it into a class so that we can define the thread proc as a static function instead of a lambda.
All of the methods are static; the class is just used to contain the implementation details.

Differential Revision: https://phabricator.services.mozilla.com/D212391
This commit is contained in:
James Teh 2024-06-03 21:30:17 +00:00
parent 9b0f0d66e0
commit 5c6a8e23d4

View file

@ -155,7 +155,11 @@ static bool FindHandle(const ComparatorFnT& aComparator) {
return false;
}
static void GetUiaClientPidsWin11(nsTArray<DWORD>& aPids) {
class GetUiaClientPidsWin11 {
public:
static void Run(nsTArray<DWORD>& aPids);
private:
struct HandleAndPid {
explicit HandleAndPid(HANDLE aHandle) : mHandle(aHandle) {}
HANDLE mHandle;
@ -167,6 +171,33 @@ static void GetUiaClientPidsWin11(nsTArray<DWORD>& aPids) {
// allow for some extra.
using HandlesAndPids = AutoTArray<HandleAndPid, 128>;
struct ThreadData {
explicit ThreadData(HandlesAndPids& aHandlesAndPids)
: mHandlesAndPids(aHandlesAndPids) {}
HandlesAndPids& mHandlesAndPids;
// Keeps track of the current index in mHandlesAndPids that is being
// queried. When the thread is (re)started, it starts querying from this
// index.
size_t mCurrentIndex = 0;
};
static DWORD WINAPI QueryThreadProc(LPVOID aParameter) {
// WARNING! Because this thread may be terminated unexpectedly due to a
// hang, it must not do anything which acquires resources, allocates memory,
// non-atomically modifies state, etc. It may not get a chance to clean up.
auto& data = *(ThreadData*)aParameter;
for (; data.mCurrentIndex < data.mHandlesAndPids.Length();
++data.mCurrentIndex) {
auto& entry = data.mHandlesAndPids[data.mCurrentIndex];
// Counter-intuitively, for UIA pipes, we're the client and the remote
// process is the server.
::GetNamedPipeServerProcessId(entry.mHandle, &entry.mPid);
}
return 0;
};
};
void GetUiaClientPidsWin11::Run(nsTArray<DWORD>& aPids) {
// 1. Get all handles of interest in our process.
HandlesAndPids handlesAndPids;
const DWORD ourPid = ::GetCurrentProcessId();
@ -185,35 +216,12 @@ static void GetUiaClientPidsWin11(nsTArray<DWORD>& aPids) {
// the process id of the remote end. We must use a background thread to query
// pipes because this can hang on some pipes and there's no way to prevent
// this other than terminating the thread. See bug 1899211 for more details.
struct ThreadData {
explicit ThreadData(HandlesAndPids& aHandlesAndPids)
: mHandlesAndPids(aHandlesAndPids) {}
HandlesAndPids& mHandlesAndPids;
// Keeps track of the current index in mHandlesAndPids that is being
// queried. When the thread is (re)started, it starts querying from this
// index.
size_t mCurrentIndex = 0;
};
ThreadData threadData(handlesAndPids);
auto queryThreadProc = [](LPVOID aParameter) -> DWORD {
// WARNING! Because this thread may be terminated unexpectedly due to a
// hang, it must not do anything which acquires resources, allocates memory,
// non-atomically modifies state, etc. It may not get a chance to clean up.
auto& data = *(ThreadData*)aParameter;
for (; data.mCurrentIndex < data.mHandlesAndPids.Length();
++data.mCurrentIndex) {
auto& entry = data.mHandlesAndPids[data.mCurrentIndex];
// Counter-intuitively, for UIA pipes, we're the client and the remote
// process is the server.
::GetNamedPipeServerProcessId(entry.mHandle, &entry.mPid);
}
return 0;
};
while (threadData.mCurrentIndex < handlesAndPids.Length()) {
// We use CreateThread here rather than Gecko's threading support because
// we may terminate this thread and we must be certain it hasn't acquired
// any resources which need to be cleaned up.
nsAutoHandle thread(::CreateThread(nullptr, 0, queryThreadProc,
nsAutoHandle thread(::CreateThread(nullptr, 0, QueryThreadProc,
(LPVOID)&threadData, 0, nullptr));
if (!thread) {
return;
@ -403,7 +411,7 @@ void Compatibility::GetUiaClientPids(nsTArray<DWORD>& aPids) {
}
Telemetry::AutoTimer<Telemetry::A11Y_UIA_DETECTION_TIMING_MS> timer;
if (IsWin11OrLater()) {
GetUiaClientPidsWin11(aPids);
GetUiaClientPidsWin11::Run(aPids);
} else {
if (DWORD pid = GetUiaClientPidWin10()) {
aPids.AppendElement(pid);