80 lines · plain
1//==- llvm/Support/Windows/Jobserver.inc - Windows Jobserver Impl -*- C++ -*-=//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the Windows-specific parts of the JobserverClient class.10// On Windows, the jobserver is implemented using a named semaphore.11//12//===----------------------------------------------------------------------===//13 14#include "llvm/Support/Windows/WindowsSupport.h"15#include <atomic>16#include <cassert>17 18namespace llvm {19/// The constructor for the Windows jobserver client. It attempts to open a20/// handle to an existing named semaphore, the name of which is provided by21/// GNU make in the --jobserver-auth argument. If the semaphore is opened22/// successfully, the client is marked as initialized.23JobserverClientImpl::JobserverClientImpl(const JobserverConfig &Config) {24 Semaphore = (void *)::OpenSemaphoreA(SEMAPHORE_MODIFY_STATE | SYNCHRONIZE,25 FALSE, Config.Path.c_str());26 if (Semaphore != nullptr)27 IsInitialized = true;28}29 30/// The destructor closes the handle to the semaphore, releasing the resource.31JobserverClientImpl::~JobserverClientImpl() {32 if (Semaphore != nullptr)33 ::CloseHandle((HANDLE)Semaphore);34}35 36/// Tries to acquire a job slot. The first call always returns the implicit37/// slot. Subsequent calls use a non-blocking wait on the semaphore38/// (`WaitForSingleObject` with a timeout of 0). If the wait succeeds, the39/// semaphore's count is decremented, and an explicit job slot is acquired.40/// If the wait times out, it means no slots are available, and an invalid41/// slot is returned.42JobSlot JobserverClientImpl::tryAcquire() {43 if (!IsInitialized)44 return JobSlot();45 46 // First, grant the implicit slot.47 if (HasImplicitSlot.exchange(false, std::memory_order_acquire)) {48 return JobSlot::createImplicit();49 }50 51 // Try to acquire a slot from the semaphore without blocking.52 if (::WaitForSingleObject((HANDLE)Semaphore, 0) == WAIT_OBJECT_0) {53 // The explicit token value is arbitrary on Windows, as the semaphore54 // count is the real resource.55 return JobSlot::createExplicit(1);56 }57 58 return JobSlot(); // Invalid slot59}60 61/// Releases a job slot back to the pool. If the slot is implicit, it simply62/// resets a flag. For an explicit slot, it increments the semaphore's count63/// by one using `ReleaseSemaphore`, making the slot available to other64/// processes.65void JobserverClientImpl::release(JobSlot Slot) {66 if (!IsInitialized || !Slot.isValid())67 return;68 69 if (Slot.isImplicit()) {70 [[maybe_unused]] bool was_already_released =71 HasImplicitSlot.exchange(true, std::memory_order_release);72 assert(!was_already_released && "Implicit slot released twice");73 return;74 }75 76 // Release the slot by incrementing the semaphore count.77 (void)::ReleaseSemaphore((HANDLE)Semaphore, 1, NULL);78}79} // namespace llvm80