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