• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef SYNC_SEMAPHORE_H
17 #define SYNC_SEMAPHORE_H
18 
19 #include <atomic>
20 #include <chrono>
21 #include <thread>
22 #include <mutex>
23 #include <condition_variable>
24 #include "sched/execute_ctx.h"
25 #include "delayed_worker.h"
26 #ifndef _MSC_VER
27 #include <unistd.h>
28 #include <sys/syscall.h>
29 #include <linux/futex.h>
30 #endif
31 
32 namespace ffrt {
33 #ifndef _MSC_VER
34 class semaphore {
35     uint64_t data;
36 
37 public:
semaphore()38     semaphore() : data(0)
39     {
40     }
semaphore(uint32_t d)41     semaphore(uint32_t d) : data(d)
42     {
43     }
44     semaphore(semaphore const&) = delete;
45     void operator=(semaphore const&) = delete;
46 
acquire()47     void acquire()
48     {
49         const uint64_t w = static_cast<uint64_t>(1) << 32;
50 
51         uint64_t d = __atomic_fetch_add(&data, w, __ATOMIC_RELAXED);
52         for (;;) {
53             // RunnableTaskNumber == 0 ?
54             if (static_cast<uint32_t>(d) == 0) {
55                 // RQ is empty, then sleep
56                 syscall(SYS_futex, &data, FUTEX_WAIT_PRIVATE, 0, nullptr, nullptr, 0);
57                 d = __atomic_load_n(&data, __ATOMIC_RELAXED);
58             } else if (__atomic_compare_exchange_n(&data, &d, d - 1 - w, 1, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
59                 break;
60             }
61         }
62     }
63 
release()64     void release()
65     {
66         // increase RunnableTaskNumber
67         uint64_t d = __atomic_fetch_add(&data, 1, __ATOMIC_RELEASE);
68         // overflow
69         if (static_cast<uint32_t>(d) == ~0u) {
70             abort();
71         }
72         // if RunnableTaskNumber == 0 && SleepWorkerNumber > 0, then wake up sleep worker
73         // if RQ is empty before new task is enqueued, RunnableTaskNumber is from 0 to 1
74         if (static_cast<uint32_t>(d) == 0 && (d >> 32) > 0) {
75             syscall(SYS_futex, &data, FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0);
76         }
77 
78         // if RunnableTaskNumber >= 4 && SleepWorkerNumber > 0 , then wake up another sleep worker
79         if (static_cast<uint32_t>(d) >= 4 && (d >> 32) > 0) {
80             syscall(SYS_futex, &data, FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0);
81         }
82     }
83 };
84 #endif
85 } // namespace ffrt
86 #endif
87