summaryrefslogtreecommitdiff
path: root/platform/darwin/src/async_task.cpp
blob: 48457d24a8dfbc72b3d74dabc8ddd436c2c97354 (plain)
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
#include <mbgl/util/async_task.hpp>

#include <CoreFoundation/CoreFoundation.h>

#include <atomic>

namespace mbgl {
namespace util {

class AsyncTask::Impl {
public:
    Impl(std::function<void()>&& fn)
        : task(std::move(fn)),
          loop(CFRunLoopGetCurrent()) {
        CFRunLoopSourceContext context = {
            0,
            this,
            nullptr,
            nullptr,
            nullptr,
            nullptr,
            nullptr,
            nullptr,
            nullptr,
            perform
        };
        source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
        CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes);
    }

    ~Impl() {
        CFRunLoopSourceInvalidate(source);
        CFRelease(source);
    }

    void maySend() {
        if (!queued.test_and_set()) {
            CFRunLoopSourceSignal(source);
            CFRunLoopWakeUp(loop);
        }
    }

    void runTask() {
        queued.clear();
        task();
    }

private:
    static void perform(void* info) {
        reinterpret_cast<Impl*>(info)->runTask();
    }

    std::function<void()> task;
    std::atomic_flag queued = ATOMIC_FLAG_INIT;

    CFRunLoopRef loop;
    CFRunLoopSourceRef source;
};

AsyncTask::AsyncTask(std::function<void()>&& fn)
    : impl(std::make_unique<Impl>(std::move(fn))) {
}

AsyncTask::~AsyncTask() = default;

void AsyncTask::send() {
    impl->maySend();
}

} // namespace util
} // namespace mbgl