• 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 <unistd.h>
25 #include <sys/syscall.h>
26 #include <linux/futex.h>
27 #include "sched/execute_ctx.h"
28 #include "delayed_worker.h"
29 
30 namespace ffrt {
31 class semaphore {
32     uint64_t data;
33 
34 public:
semaphore()35     semaphore() : data(0)
36     {
37     }
semaphore(uint32_t d)38     semaphore(uint32_t d) : data(d)
39     {
40     }
41     semaphore(semaphore const&) = delete;
42     void operator=(semaphore const&) = delete;
43 
acquire()44     void acquire()
45     {
46         const uint64_t w = static_cast<uint64_t>(1) << 32;
47 
48         uint64_t d = __atomic_fetch_add(&data, w, __ATOMIC_RELAXED);
49         for (;;) {
50             // RunnableTaskNumber == 0 ?
51             if (static_cast<uint32_t>(d) == 0) {
52                 // RQ is empty, then sleep
53                 syscall(SYS_futex, &data, FUTEX_WAIT_PRIVATE, 0, nullptr, nullptr, 0);
54                 d = __atomic_load_n(&data, __ATOMIC_RELAXED);
55             } else if (__atomic_compare_exchange_n(&data, &d, d - 1 - w, 1, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
56                 break;
57             }
58         }
59     }
60 
release()61     void release()
62     {
63         // increase RunnableTaskNumber
64         uint64_t d = __atomic_fetch_add(&data, 1, __ATOMIC_RELEASE);
65         // overflow
66         if (static_cast<uint32_t>(d) == ~0u) {
67             abort();
68         }
69         // if RunnableTaskNumber == 0 && SleepWorkerNumber > 0, then wake up sleep worker
70         // if RQ is empty before new task is enqueued, RunnableTaskNumber is from 0 to 1
71         if (static_cast<uint32_t>(d) == 0 && (d >> 32) > 0) {
72             syscall(SYS_futex, &data, FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0);
73         }
74 
75         // if RunnableTaskNumber >= 4 && SleepWorkerNumber > 0 , then wake up another sleep worker
76         if (static_cast<uint32_t>(d) >= 4 && (d >> 32) > 0) {
77             syscall(SYS_futex, &data, FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0);
78         }
79     }
80 };
81 } // namespace ffrt
82 #endif
83