Coverage Report

Created: 2025-07-23 06:16

/src/pistache/include/pistache/os.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * SPDX-FileCopyrightText: 2015 Mathieu Stefani
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
5
 */
6
7
/* os.h
8
   Mathieu Stefani, 13 August 2015
9
10
   Operating system specific functions
11
*/
12
13
#pragma once
14
15
#include <pistache/winornix.h>
16
17
#include <pistache/common.h>
18
#include <pistache/config.h>
19
#include <pistache/eventmeth.h>
20
#include <pistache/flags.h>
21
22
#include <bitset>
23
#include <chrono>
24
#include <memory>
25
#include <mutex>
26
#include <vector>
27
28
namespace Pistache
29
{
30
    // Note: Fd is defined in eventmeth.h
31
32
    unsigned int hardware_concurrency();
33
    bool make_non_blocking(em_socket_t fd);
34
35
    class CpuSet
36
    {
37
    public:
38
        static constexpr size_t Size = 1024;
39
40
        CpuSet();
41
        explicit CpuSet(std::initializer_list<size_t> cpus);
42
43
        void clear();
44
        CpuSet& set(size_t cpu);
45
        CpuSet& unset(size_t cpu);
46
47
        CpuSet& set(std::initializer_list<size_t> cpus);
48
        CpuSet& unset(std::initializer_list<size_t> cpus);
49
50
        CpuSet& setRange(size_t begin, size_t end);
51
        CpuSet& unsetRange(size_t begin, size_t end);
52
53
        bool isSet(size_t cpu) const;
54
        size_t count() const;
55
56
#ifdef _POSIX_C_SOURCE
57
        cpu_set_t toPosix() const;
58
#endif
59
60
    private:
61
        std::bitset<Size> bits;
62
    };
63
64
    namespace Polling
65
    {
66
67
        enum class Mode { Level,
68
                          Edge };
69
70
        enum class NotifyOn {
71
            None = 0,
72
73
            Read     = 1,
74
            Write    = Read << 1,
75
            Hangup   = Read << 2,
76
            Shutdown = Read << 3
77
        };
78
79
        DECLARE_FLAGS_OPERATORS(NotifyOn)
80
81
#ifdef _USE_LIBEVENT
82
        using TagValue      = Fd;
83
        using TagValueConst = const Fd;
84
#define TAG_VALUE_EMPTY NULL
85
#else
86
        using TagValue      = uint64_t;
87
        using TagValueConst = uint64_t;
88
#endif
89
90
        struct Tag
91
        {
92
            friend class Epoll;
93
94
            explicit constexpr Tag(TagValue value)
95
0
                : value_(value)
96
0
            { }
97
98
0
            constexpr TagValue value() const { return value_; }
99
0
            uint64_t valueU64() const { return (PS_FD_CAST_TO_UNUM(uint64_t, value_)); }
100
101
#ifndef _USE_LIBEVENT
102
            constexpr
103
#endif
104
                uint64_t
105
                actualFdU64Value() const
106
0
            {
107
0
#ifdef _USE_LIBEVENT
108
0
                if (value_ == nullptr)
109
0
                    return (static_cast<uint64_t>(-1));
110
0
                em_socket_t actual_fd = GET_ACTUAL_FD(value_);
111
0
                return (static_cast<uint64_t>(actual_fd));
112
0
#else
113
0
                return (value_);
114
0
#endif
115
0
            }
116
117
            friend constexpr bool operator==(Tag lhs, Tag rhs);
118
119
        private:
120
            TagValue value_;
121
        };
122
123
        inline constexpr bool operator==(Tag lhs, Tag rhs)
124
0
        {
125
0
            return lhs.value_ == rhs.value_;
126
0
        }
127
128
        struct Event
129
        {
130
            explicit Event(Tag _tag);
131
132
            Flags<NotifyOn> flags;
133
            Tag tag;
134
        };
135
136
        class Epoll
137
        {
138
        public:
139
            Epoll();
140
            ~Epoll();
141
142
            void addFd(Fd fd, Flags<NotifyOn> interest, Tag tag,
143
                       [[maybe_unused]] Mode mode = Mode::Level);
144
            void addFdOneShot(Fd fd, Flags<NotifyOn> interest, Tag tag,
145
                              Mode mode = Mode::Level);
146
147
            void removeFd(Fd fd);
148
            void rearmFd(Fd fd, Flags<NotifyOn> interest, Tag tag,
149
                         [[maybe_unused]] Mode mode = Mode::Level);
150
151
            int poll(std::vector<Event>& events, const std::chrono::milliseconds timeout = std::chrono::milliseconds(-1)) const;
152
153
            // reg_unreg_mutex_ must be locked for a call to poll(...) and
154
            // remain locked while the caller handles any returned events, to
155
            // prevent this poller being unregistered while the handling is
156
            // going on (see also unregisterPoller, plus the long comment for
157
            // reactor_ in class Handler)
158
            mutable std::mutex reg_unreg_mutex_;
159
160
#ifdef _USE_LIBEVENT
161
            static Fd em_event_new(
162
                em_socket_t actual_fd, // file desc, signal, or -1
163
                short flags, // EVM_... flags
164
                // For setfd and setfl arg:
165
                //   F_SETFDL_NOTHING - change nothing
166
                //   Zero or pos number that is not
167
                //   F_SETFDL_NOTHING - set flags to value of arg,
168
                //   and clear any other flags
169
                //   Neg number that is not F_SETFDL_NOTHING - set
170
                //   flags that are set in (0 - arg), but don't
171
                //   clear any flags
172
                int f_setfd_flags, // e.g. FD_CLOEXEC
173
                int f_setfl_flags // e.g. O_NONBLOCK
174
            );
175
176
            Fd em_timer_new(PST_CLOCK_ID_T clock_id,
177
                            // For setfd and setfl arg:
178
                            //   F_SETFDL_NOTHING - change nothing
179
                            //   Zero or pos number that is not
180
                            //   F_SETFDL_NOTHING - set flags to value of
181
                            //   arg, and clear any other flags
182
                            //   Neg number that is not F_SETFDL_NOTHING
183
                            //   - set flags that are set in (0 - arg),
184
                            //   but don't clear any flags
185
                            int f_setfd_flags, // e.g. FD_CLOEXEC
186
                            int f_setfl_flags); // e.g. O_NONBLOCK
187
188
            // For "eventfd-style" descriptors
189
            // Note that FdEventFd does not have an "actual fd" that the caller
190
            // can access; the caller must use FdEventFd's member functions
191
            // instead
192
            static FdEventFd em_eventfd_new(unsigned int initval,
193
                                            int f_setfd_flags, // e.g. FD_CLOEXEC
194
                                            int f_setfl_flags); // e.g. O_NONBLOCK
195
196
            std::shared_ptr<EventMethEpollEquiv> getEventMethEpollEquiv()
197
            {
198
                return (epoll_fd);
199
            }
200
#endif
201
202
        private:
203
#ifndef _USE_LIBEVENT
204
            static int toEpollEvents(const Flags<NotifyOn>& interest);
205
            static Flags<NotifyOn> toNotifyOn(int events);
206
#endif
207
208
#ifdef _USE_LIBEVENT
209
            std::shared_ptr<EventMethEpollEquiv> epoll_fd;
210
#else
211
            Fd epoll_fd;
212
#endif
213
        };
214
215
    } // namespace Polling
216
217
    class NotifyFd
218
    {
219
    public:
220
        NotifyFd();
221
        ~NotifyFd();
222
223
        Polling::Tag bind(Polling::Epoll& poller);
224
        void unbind(Polling::Epoll& poller);
225
226
        bool isBound() const;
227
228
        Polling::Tag tag() const;
229
230
        void notify() const;
231
232
        void read() const;
233
        bool tryRead() const;
234
235
    private:
236
        Fd event_fd;
237
    };
238
239
} // namespace Pistache