1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
//==- 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
|