80 lines
3.1 KiB
C++
80 lines
3.1 KiB
C++
//==- llvm/Support/Windows/Jobserver.inc - Windows Jobserver Impl -*- C++ -*-=//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the Windows-specific parts of the JobserverClient class.
|
|
// On Windows, the jobserver is implemented using a named semaphore.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Support/Windows/WindowsSupport.h"
|
|
#include <atomic>
|
|
#include <cassert>
|
|
|
|
namespace llvm {
|
|
/// The constructor for the Windows jobserver client. It attempts to open a
|
|
/// handle to an existing named semaphore, the name of which is provided by
|
|
/// GNU make in the --jobserver-auth argument. If the semaphore is opened
|
|
/// successfully, the client is marked as initialized.
|
|
JobserverClientImpl::JobserverClientImpl(const JobserverConfig &Config) {
|
|
Semaphore = (void *)::OpenSemaphoreA(SEMAPHORE_MODIFY_STATE | SYNCHRONIZE,
|
|
FALSE, Config.Path.c_str());
|
|
if (Semaphore != nullptr)
|
|
IsInitialized = true;
|
|
}
|
|
|
|
/// The destructor closes the handle to the semaphore, releasing the resource.
|
|
JobserverClientImpl::~JobserverClientImpl() {
|
|
if (Semaphore != nullptr)
|
|
::CloseHandle((HANDLE)Semaphore);
|
|
}
|
|
|
|
/// Tries to acquire a job slot. The first call always returns the implicit
|
|
/// slot. Subsequent calls use a non-blocking wait on the semaphore
|
|
/// (`WaitForSingleObject` with a timeout of 0). If the wait succeeds, the
|
|
/// semaphore's count is decremented, and an explicit job slot is acquired.
|
|
/// If the wait times out, it means no slots are available, and an invalid
|
|
/// slot is returned.
|
|
JobSlot JobserverClientImpl::tryAcquire() {
|
|
if (!IsInitialized)
|
|
return JobSlot();
|
|
|
|
// First, grant the implicit slot.
|
|
if (HasImplicitSlot.exchange(false, std::memory_order_acquire)) {
|
|
return JobSlot::createImplicit();
|
|
}
|
|
|
|
// Try to acquire a slot from the semaphore without blocking.
|
|
if (::WaitForSingleObject((HANDLE)Semaphore, 0) == WAIT_OBJECT_0) {
|
|
// The explicit token value is arbitrary on Windows, as the semaphore
|
|
// count is the real resource.
|
|
return JobSlot::createExplicit(1);
|
|
}
|
|
|
|
return JobSlot(); // Invalid slot
|
|
}
|
|
|
|
/// Releases a job slot back to the pool. If the slot is implicit, it simply
|
|
/// resets a flag. For an explicit slot, it increments the semaphore's count
|
|
/// by one using `ReleaseSemaphore`, making the slot available to other
|
|
/// processes.
|
|
void JobserverClientImpl::release(JobSlot Slot) {
|
|
if (!IsInitialized || !Slot.isValid())
|
|
return;
|
|
|
|
if (Slot.isImplicit()) {
|
|
[[maybe_unused]] bool was_already_released =
|
|
HasImplicitSlot.exchange(true, std::memory_order_release);
|
|
assert(!was_already_released && "Implicit slot released twice");
|
|
return;
|
|
}
|
|
|
|
// Release the slot by incrementing the semaphore count.
|
|
(void)::ReleaseSemaphore((HANDLE)Semaphore, 1, NULL);
|
|
}
|
|
} // namespace llvm
|