root/lang/c/partty/fdio/multiplexer_bsd_kqueue.h @ 3319

Revision 3319, 5.0 kB (checked in by frsyuki, 5 years ago)

lang/c/partty: imported.

Line 
1/*
2 * FDIO
3 *
4 * Copyright (c) 2007 FURUHASHI Sadayuki
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#ifndef FDIO_MULTIPLEXER_BSD_KQUEUE_H__
26#define FDIO_MULTIPLEXER_BSD_KQUEUE_H__ 1
27
28#include "fdio/multiplexer_common.h"
29#include <sys/event.h>  // kqueue
30#include <sys/time.h>
31#include <valarray>
32#include <bitset>
33#include <limits>
34
35namespace FDIO {
36
37template <bool oneshot, bool threadsafe>
38class BSDKqueueMultiplexer {
39public:
40        typedef int fd_type;
41        typedef short index_type;
42        typedef enum {
43                EVENT_IN  = EVFILT_READ,
44                EVENT_OUT = EVFILT_WRITE,
45        } observe_type;
46        typedef short observe_bitmap_t;
47public:
48        class BSDKqueueEvents {
49        public:
50                struct Event {
51                        friend class BSDKqueueMultiplexer;
52                        Event(const struct kevent& kev) :
53                                fd(kev.ident),
54                                events(kev.filter),
55                                observed( (short)(int)kev.udata ) {}
56                                        // void* -> shortのキャストは危険だが、たぶん動く
57                        Event() : fd(-1), events(0) {}
58                        int fd;
59                        observe_bitmap_t events;
60                private:
61                        short observed;
62                };
63                typedef Event ev_t;
64        public:
65                Event next(void)
66                {
67                        if( m_current < m_num ) {
68                                return Event(m_results[m_current++]);
69                        } else {
70                                return Event();
71                        }
72                }
73        public:
74                BSDKqueueEvents(const std::valarray<struct kevent>& results, int num) :
75                                        m_current(0),
76                                        m_num(num),
77                                        m_results(results)
78                {
79                        if( num < 0 && errno != EINTR ) {
80                                throw MultiplexerWaitException(errno, "kevent() wait");
81                        }
82                }
83        private:
84                size_t m_current;
85                const size_t m_num;
86                const std::valarray<struct kevent>& m_results;
87        private:
88                BSDKqueueEvents();
89        };
90        typedef BSDKqueueEvents events_type;
91private:
92        static const int MAX_EVENTS = 8;
93public:
94        BSDKqueueMultiplexer() : m_results(MAX_EVENTS)
95        {
96                if( (m_kqueue_fd = kqueue()) < 0 ) {
97                        throw MultiplexerInitializeException(errno, "kqueue() initialize");
98                }
99        }
100
101        index_type add(int fd, observe_bitmap_t events)
102        {
103                struct kevent kev;
104
105                EV_SET(&kev, fd, events, EV_ADD | (oneshot ? EV_ONESHOT : 0), 0, 0, (void*)events);
106                        // short -> void* のキャストは危険だが、たぶん動く
107
108                if( kevent(m_kqueue_fd, &kev, 1, NULL, 0, NULL) < 0 ) {
109                        throw MultiplexerAddException(errno, "kevent() add");
110                }
111
112                return events;
113
114                /*
115                struct timespec ts;
116                ts.tv_sec  = 0;
117                ts.tv_nsec = 0;
118                */
119        }
120
121        void reactivate(index_type index, int fd, observe_bitmap_t events)
122        {
123                struct kevent kev;
124
125                EV_SET(&kev, fd, events, EV_ADD | (oneshot ? EV_ONESHOT : 0), 0, 0, (void*)events);
126                        // short -> void* のキャストは危険だが、たぶん動く
127
128                if( kevent(m_kqueue_fd, &kev, 1, NULL, 0, NULL) < 0 ) {
129                        throw MultiplexerReactivateException(errno, "kevent() reactivate");
130                }
131
132                /*
133                struct timespec ts;
134                ts.tv_sec  = 0;
135                ts.tv_nsec = 0;
136                */
137        }
138        void reactivate(typename events_type::ev_t ev, observe_bitmap_t events)
139        {
140                reactivate(ev.observed, ev.fd, events);
141        }
142
143        void remove(index_type index, int fd)
144        {
145                if( index & EVFILT_READ && index & EVFILT_WRITE ) {
146                        struct kevent kev[2];
147                        EV_SET(&kev[0], fd, EVFILT_READ,  EV_DELETE, 0, 0, NULL);
148                        EV_SET(&kev[1], fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
149                        if( kevent(m_kqueue_fd, kev, 2, NULL, 0, NULL) < 0 ) {
150                                throw MultiplexerRemoveException(errno, "kevent() remove");
151                        }
152                } else {
153                        struct kevent kev;
154                        EV_SET(&kev, fd, index, EV_DELETE, 0, 0, NULL);
155                        if( kevent(m_kqueue_fd, &kev, 1, NULL, 0, NULL) < 0 ) {
156                                throw MultiplexerRemoveException(errno, "kevent() remove");
157                        }
158                }
159        }
160
161        void remove(typename events_type::ev_t ev)
162        {
163                remove(ev.observed, ev.fd);
164        }
165
166        events_type wait(int timeout_msec)
167        {
168                struct timespec ts;
169                ts.tv_sec  = timeout_msec / 1000;
170                ts.tv_nsec = (timeout_msec % 1000) * 1000000;
171
172                return BSDKqueueEvents(
173                                m_results,
174                                kevent(m_kqueue_fd, NULL, 0, &m_results[0], m_results.size(), &ts)
175                                );
176        }
177
178        events_type wait(void)
179        {
180                return BSDKqueueEvents(
181                                m_results,
182                                kevent(m_kqueue_fd, NULL, 0, &m_results[0], m_results.size(), NULL)
183                                );
184        }
185
186private:
187        int m_kqueue_fd;
188        std::valarray<struct kevent> m_results;
189};
190
191
192}  // namespace FDIO
193
194#endif /* multiplexer_bsd_kqueue.h */
Note: See TracBrowser for help on using the browser.