xref: /f-stack/app/micro_thread/kqueue_proxy.h (revision 03df98de)
1 
2 /**
3  * Tencent is pleased to support the open source community by making MSEC available.
4  *
5  * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
6  *
7  * Licensed under the GNU General Public License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License. You may
9  * obtain a copy of the License at
10  *
11  *     https://opensource.org/licenses/GPL-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software distributed under the
14  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
15  * either express or implied. See the License for the specific language governing permissions
16  * and limitations under the License.
17  */
18 
19 
20 /**
21  *  @filename kqueue.h
22  *  @info     kqueue for micro thread manage
23  */
24 
25 #ifndef _KQUEUE_PROXY___
26 #define _KQUEUE_PROXY___
27 
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <sys/queue.h>
31 
32 #include "ff_api.h"
33 
34 #include <set>
35 #include <vector>
36 using std::set;
37 using std::vector;
38 
39 #define kqueue_assert(statement)
40 //#define kqueue_assert(statement) assert(statement)
41 
42 namespace NS_MICRO_THREAD {
43 
44 #define KQ_EVENT_NONE 0
45 #define KQ_EVENT_READ 1
46 #define KQ_EVENT_WRITE 2
47 
48 /**
49  * @brief add more detail for linux <sys/queue.h>, freebsd and University of California
50  * @info  queue.h version 8.3 (suse)  diff version 8.5 (tlinux)
51  */
52 #ifndef TAILQ_CONCAT
53 
54 #define TAILQ_EMPTY(head)   ((head)->tqh_first == NULL)
55 #define TAILQ_FIRST(head)   ((head)->tqh_first)
56 #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
57 
58 #define TAILQ_LAST(head, headname) \
59         (*(((struct headname *)((head)->tqh_last))->tqh_last))
60 
61 #define TAILQ_FOREACH(var, head, field)                                     \
62         for ((var) = TAILQ_FIRST((head));                                   \
63              (var);                                                         \
64              (var) = TAILQ_NEXT((var), field))
65 
66 #define TAILQ_CONCAT(head1, head2, field)                                   \
67 do {                                                                        \
68     if (!TAILQ_EMPTY(head2)) {                                              \
69         *(head1)->tqh_last = (head2)->tqh_first;                            \
70         (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;             \
71         (head1)->tqh_last = (head2)->tqh_last;                              \
72         TAILQ_INIT((head2));                                                \
73     }                                                                       \
74 } while (0)
75 
76 #endif
77 
78 #ifndef TAILQ_FOREACH_SAFE      // tlinux no this define
79 #define TAILQ_FOREACH_SAFE(var, head, field, tvar)                          \
80         for ((var) = TAILQ_FIRST((head));                                   \
81              (var) && ((tvar) = TAILQ_NEXT((var), field), 1);               \
82              (var) = (tvar))
83 #endif
84 
85 
86 
87 
88 /******************************************************************************/
89 /*  Kqueue proxy definition and implementation                                */
90 /******************************************************************************/
91 
92 class KqueueProxy;
93 class MicroThread;
94 
95 class KqueuerObj
96 {
97     protected:
98         int _fd;
99         int _events;
100         int _revents;
101         int _type;
102         MicroThread* _thread;
103 
104     public:
105 
106         TAILQ_ENTRY(KqueuerObj) _entry;
107 
108         explicit KqueuerObj(int fd = -1) {
109             _fd       = fd;
110             _events   = 0;
111             _revents  = 0;
112             _type     = 0;
113             _thread   = NULL;
114         };
115         virtual ~KqueuerObj(){};
116 
117         virtual int InputNotify();
118         virtual int OutputNotify();
119         virtual int HangupNotify();
120         virtual int KqueueCtlAdd(void* args);
121         virtual int KqueueCtlDel(void* args);
122 
123         void EnableInput() {    _events |= KQ_EVENT_READ; };
124 
125         void EnableOutput() {     _events |= KQ_EVENT_WRITE; };
126 
127         void DisableInput() {   _events &= ~KQ_EVENT_READ; };
128 
129         void DisableOutput() {    _events &= ~KQ_EVENT_WRITE; };
130 
131         int GetOsfd() { return _fd; };
132         void SetOsfd(int fd) {   _fd = fd; };
133 
134         int GetEvents() { return _events; };
135         void SetRcvEvents(int revents) { _revents = revents; };
136         int GetRcvEvents() { return _revents; };
137 
138         int GetNtfyType() {    return _type; };
139         virtual void Reset() {
140             _fd      = -1;
141             _events  = 0;
142             _revents = 0;
143             _type    = 0;
144             _thread  = NULL;
145         };
146 
147         void SetOwnerThread(MicroThread* thread) {      _thread = thread; };
148         MicroThread* GetOwnerThread() {        return _thread; };
149 
150 };
151 
152 typedef TAILQ_HEAD(__KqFdList, KqueuerObj) KqObjList;
153 typedef struct kevent KqEvent;
154 
155 
156 class KqFdRef
157 {
158 private:
159     int _wr_ref;
160     int _rd_ref;
161     int _events;
162     int _revents;
163     KqueuerObj* _kqobj;
164 
165 public:
166 
167     KqFdRef() {
168         _wr_ref  = 0;
169         _rd_ref  = 0;
170         _events  = 0;
171         _revents = 0;
172         _kqobj   = NULL;
173     };
174     ~KqFdRef(){};
175 
176     void SetListenEvents(int events) {
177         _events = events;
178     };
179     int GetListenEvents() {
180         return _events;
181     };
182 
183     void SetNotifyObj(KqueuerObj* ntfy) {
184         _kqobj = ntfy;
185     };
186     KqueuerObj* GetNotifyObj() {
187         return _kqobj;
188     };
189 
190     void AttachEvents(int event) {
191         if (event & KQ_EVENT_READ) {
192             _rd_ref++;
193         }
194         if (event & KQ_EVENT_WRITE){
195             _wr_ref++;
196         }
197     };
198     void DetachEvents(int event) {
199         if (event & KQ_EVENT_READ) {
200             if (_rd_ref > 0) {
201                 _rd_ref--;
202             } else {
203                 _rd_ref = 0;
204             }
205         }
206         if (event & KQ_EVENT_WRITE){
207             if (_wr_ref > 0) {
208                 _wr_ref--;
209             } else {
210                 _wr_ref = 0;
211             }
212         }
213     };
214 
215 
216     int ReadRefCnt() { return _rd_ref; };
217     int WriteRefCnt() { return _wr_ref; };
218 
219 };
220 
221 
222 class KqueueProxy
223 {
224     public:
225         static const int DEFAULT_MAX_FD_NUM = 100000;
226 
227     private:
228         int                       _kqfd;
229         int                       _maxfd;
230         KqEvent*                  _evtlist;
231         KqFdRef*                  _kqrefs;
232 
233     public:
234         KqueueProxy();
235         virtual ~KqueueProxy(){};
236 
237         int InitKqueue(int max_num);
238         void TermKqueue(void);
239 
240         virtual int KqueueGetTimeout(void) { return 0; };
241         virtual bool KqueueSchedule(KqObjList* fdlist, KqueuerObj* fd, int timeout) { return false; };
242 
243         bool KqueueAdd(KqObjList& fdset);
244         bool KqueueDel(KqObjList& fdset);
245         void KqueueDispatch(void);
246         bool KqueueAddObj(KqueuerObj* obj);
247         bool KqueueDelObj(KqueuerObj* obj);
248         bool KqueueCtrlAdd(int fd, int new_events);
249         bool KqueueCtrlDel(int fd, int new_events);
250         bool KqueueCtrlDelRef(int fd, int new_events, bool use_ref);
251 
252         KqFdRef* KqFdRefGet(int fd) {
253             return ((fd >= _maxfd) || (fd < 0)) ? (KqFdRef*)NULL : &_kqrefs[fd];
254         }
255 
256         void KqueueNtfyReg(int fd, KqueuerObj* obj) {
257             KqFdRef* ref = KqFdRefGet(fd);
258             if (ref) {
259                 ref->SetNotifyObj(obj);
260             }
261         };
262 
263     protected:
264         void KqueueRcvEventList(int evtfdnum);
265 };
266 
267 }
268 
269 
270 #endif
271