1/*
2 * Copyright 2012-present Facebook, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <folly/portability/Semaphore.h>
18
19#include <folly/portability/Windows.h>
20
21#include <errno.h>
22#include <mutex>
23
24#if _WIN32
25namespace folly::portability::semaphore {
26struct sem_t_ {
27 std::mutex mtx{};
28 HANDLE sema{INVALID_HANDLE_VALUE};
29 int32_t value{0};
30};
31
32int sem_init(sem_t* s, int shared, unsigned int value) {
33 // Don't support cross-process shared semaphores.
34 if (shared != 0) {
35 return -1;
36 }
37 auto sem = CreateSemaphoreA(nullptr, 0, SEM_VALUE_MAX, nullptr);
38 if (sem == 0) {
39 return -1;
40 }
41 auto ret = new sem_t_();
42 ret->sema = sem;
43 ret->value = value;
44 *s = ret;
45 return 0;
46}
47
48int sem_destroy(sem_t* s) {
49 if (!CloseHandle((*s)->sema)) {
50 return -1;
51 }
52 delete *s;
53 *s = nullptr;
54 return 0;
55}
56
57int sem_post(sem_t* s) {
58 std::lock_guard<std::mutex> lock{(*s)->mtx};
59 if ((*s)->value < SEM_VALUE_MAX) {
60 if (++(*s)->value <= 0 && !ReleaseSemaphore((*s)->sema, 1, nullptr)) {
61 --(*s)->value;
62 errno = EINVAL;
63 return -1;
64 }
65 } else {
66 errno = ERANGE;
67 return -1;
68 }
69 return 0;
70}
71
72int sem_trywait(sem_t* s) {
73 std::lock_guard<std::mutex> lock{(*s)->mtx};
74 if ((*s)->value > 0) {
75 (*s)->value--;
76 return 0;
77 } else {
78 errno = EAGAIN;
79 return -1;
80 }
81}
82
83int sem_wait(sem_t* s) {
84 int32_t value = 0;
85 {
86 std::lock_guard<std::mutex> lock{(*s)->mtx};
87 value = --(*s)->value;
88 }
89
90 if (value < 0) {
91 if (WaitForSingleObject((*s)->sema, INFINITE) != WAIT_OBJECT_0) {
92 errno = EINVAL;
93 return -1;
94 }
95 }
96 return 0;
97}
98} // namespace folly::portability::semaphore
99#endif
100