//==- 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 #include 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