├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── common ├── Makefile ├── rbtree.c ├── rbtree.h ├── rbtree_augmented.h └── rbtree_test.c ├── ev_demo.c ├── ev_httpd.c ├── ev_io.c ├── ev_loop.c ├── ev_loop.h ├── ev_timer.c └── ev_type.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Libraries 8 | *.lib 9 | *.a 10 | 11 | # Shared objects (inc. Windows DLLs) 12 | *.dll 13 | *.so 14 | *.so.* 15 | *.dylib 16 | 17 | # Executables 18 | *.exe 19 | *.out 20 | *.app 21 | *.i*86 22 | *.x86_64 23 | *.hex 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: libevlib.a ev_demo ev_httpd 2 | OBJ := ev_loop.o ev_io.o ev_timer.o 3 | CC := gcc 4 | DEBUG := -g -Wall 5 | LFLAG := -lrt 6 | 7 | libevlib.a: $(OBJ) 8 | ar crv $@ $^ 9 | 10 | ev_httpd: ev_httpd.o $(OBJ) 11 | $(CC) $(DEBUG) $< $(OBJ) -o $@ $(LFLAG) 12 | ev_demo: ev_demo.o $(OBJ) 13 | $(CC) $(DEBUG) $< $(OBJ) -o $@ $(LFLAG) 14 | 15 | ev_httpd.o: ev_httpd.c ev_loop.h ev_type.h 16 | $(CC) $(DEBUG) -c $< 17 | ev_demo.o: ev_demo.c ev_loop.h ev_type.h 18 | $(CC) $(DEBUG) -c $< 19 | 20 | ev_loop.o: ev_loop.c ev_loop.h ev_type.h 21 | $(CC) $(DEBUG) -c $< 22 | 23 | ev_io.o: ev_io.c ev_loop.h ev_type.h 24 | $(CC) $(DEBUG) -c $< 25 | ev_timer.o: ev_timer.c ev_loop.h ev_type.h 26 | $(CC) $(DEBUG) -c $< 27 | 28 | clean: 29 | rm *.o libevlib.a ev_demo ev_httpd -f 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ###目录 2 | * [ABOUT](#about) 3 | * [DEMO](#demo) 4 | * [ev_httpd](#ev_httpd) 5 | * [ev_demo](#simple_demo) 6 | * [API](#apis) 7 | * [TEST](#test) 8 | 9 | 10 | ABOUT 11 | ====== 12 | 这是一个基于epoll+timerfd的事件回调库。目前支持`io读写`事件,和`定时`事件。 13 | 14 | --- 15 | 目前在我的个人项目中,有很多地方都用到了这个事件回调库(有改动),具体用法参考 [API](#apis) 16 | * web server中用到了io事件回调来处理连接,同时用到了定时事件来处理Keep-alive的情况 17 | * 在线聊天室中后台用到了定时事件,来做ajax long polling的定时 18 | 19 | 20 | ###DEMO### 21 | 22 | **ev_httpd** 23 | * 这是一个基于此回调库而写的一个简单高效的http server, 该server能轻松应对并发问题(单进程+eventloop+IO复用+非阻塞IO). 24 | 该httpd目前的功能很简单,接收http请求,返回“hello evlib”。 25 | * 26 | ``` 27 | make 28 | ./ev_httpd 8080 29 | ``` 30 | * 打开浏览器,http://127.0.0.1:8080/ 31 | 32 | 33 | 34 | **ev demo** 35 | 36 | 这是一个最简单的demo,可以清楚的看到event loop的用法,io/timer事件相关操作的用法。 37 | `这个ev_demo,主要是监听stdin的可读事件,当stdin有数据 38 | 可读,那么打印you have data to read. 同时程序里面监听了定时事件,每隔5s打印Timeout。` 39 | 40 | ###in your program### 41 | * SYNOPSIS 42 | ``` 43 | #include "ev_loop.h" 44 | #include "ev_type.h" 45 | ``` 46 | * EXAMPLE PROGRAM 47 | ```c 48 | #include 49 | #include "ev_loop.h" 50 | #include "ev_type.h" 51 | 52 | ev_loop_t * loop = NULL; 53 | 54 | void *cb_stdin1(ev_loop_t *loop, int fd, EV_TYPE events); 55 | void *cb_timer1(ev_loop_t *loop, struct ev_timer *timer); 56 | 57 | int main() 58 | { 59 | loop = ev_create_loop(); 60 | 61 | ev_io_init(loop, 100, 1); 62 | ev_io_register(loop, 0, EV_READ, cb_stdin1, NULL); 63 | 64 | ev_timer_init(loop, 10); 65 | ev_timer_register(loop, 5.0, cb_timer1, 1, NULL); 66 | 67 | ev_run_loop(loop); 68 | return 0; 69 | } 70 | 71 | void *cb_stdin1(ev_loop_t *loop, int fd, EV_TYPE events) { 72 | printf("You have data to read\n"); 73 | return NULL; 74 | } 75 | void *cb_timer1(ev_loop_t *loop, struct ev_timer *timer) { 76 | printf("Timeout!\n"); 77 | return NULL; 78 | } 79 | 80 | ``` 81 | 82 | ###API### 83 | `具体可以在ev_loop.h ev_type.h 中查看` 84 | 85 | **event loop** 86 | 87 | * 创建事件循环 88 | 89 | ```c 90 | //创建一个 event loop并返回 91 | ev_loop_t *ev_create_loop(); 92 | ``` 93 | 94 | * 启动event loop 95 | 96 | ```c 97 | //启动Loop,开始监听各种事件 98 | int ev_run_loop(ev_loop_t *loop); 99 | ``` 100 | 101 | **io event** 102 | * 初始化io事件 103 | ```c 104 | // et = 1: 用EPOLLET 模式, =0: 用EPOLLLT模式 105 | int ev_io_init(ev_loop_t *loop, int max_ev_num, int etmodel); 106 | ``` 107 | 108 | * 注册io事件(`EV_READ, EV_WRITE`)到循环中 109 | 110 | ```c 111 | //在fd上注册感兴趣的events 112 | //当fd上events发生时,调用cb 113 | //可以重复注册,改变cb 114 | int ev_io_register(ev_loop_t*loop, int fd, EV_TYPE events, cb_func_t cb, void *ptr); 115 | ``` 116 | 117 | * 注销fd上io事件 118 | 119 | ```c 120 | //注销fd,即fd上的所有事件脱离循环 121 | int ev_io_unregister(ev_loop_t *loop, int fd); 122 | ``` 123 | 124 | * 停止io事件 125 | 126 | ```c 127 | //这个不同于注销,而是只停止某个事件,比如fd上同时注册了 128 | //可读和可写event, 那么我可以值stop可读事件 129 | int ev_io_stop(ev_loop_t *loop, int fd, EV_TYPE events); 130 | ``` 131 | **timer event** 132 | 133 | * 初始化定时事件 134 | 135 | ```c 136 | // capacity: 初始化timer可达数量 137 | int ev_timer_init(ev_loop_t *loop, int capacity); 138 | ``` 139 | 140 | * 注册定时事件 141 | 142 | ```c 143 | // timeout: 单位s,可精确到小数点后9位,也就是纳秒 144 | // repeat: 0-->只定时一次, 1-->循序定时,无穷无尽 145 | int ev_timer_register(ev_loop_t *loop, double timeout, cb_timer_t cb, uint8_t repeat, void *ptr); 146 | ``` 147 | 148 | * 注销定时事件 149 | ```c 150 | int ev_timer_unregister(ev_loop_t *loop, ev_timer_t *timer); 151 | ``` 152 | 153 | TestCase 154 | ====== 155 | * timer 156 | * 后加入的timer反而比目前已经注册的timer先到期的情况 157 | * timer 数量由0变1,和由1变0需要特别注意,都需要timerfd_settime,前者设置为给定值,后者置0 158 | * ts为0和负的情况,考虑到 159 | * 单次和无限循序定时混合test 160 | * timer 10000 count 161 | 162 | * IO 163 | 164 | * valgrind memleak test && leak fd test 165 | ``` 166 | valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./demo 167 | ``` 168 | --- 169 | -------------------------------------------------------------------------------- /common/Makefile: -------------------------------------------------------------------------------- 1 | ALL: test 2 | 3 | rbtree.o: rbtree.c 4 | gcc -c -g rbtree.c 5 | 6 | rbtest_test.o: rbtree_test.c 7 | gcc -c -g rbtree_test.c 8 | 9 | test: rbtree.o rbtree_test.o 10 | gcc rbtree_test.o rbtree.o -g -o test 11 | 12 | clean: 13 | rm rbtree.o rbtree_test.o test -f 14 | -------------------------------------------------------------------------------- /common/rbtree.c: -------------------------------------------------------------------------------- 1 | /* 2 | Red Black Trees 3 | (C) 1999 Andrea Arcangeli 4 | (C) 2002 David Woodhouse 5 | (C) 2012 Michel Lespinasse 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | 21 | linux/lib/rbtree.c 22 | */ 23 | 24 | #include 25 | #include "rbtree_augmented.h" 26 | 27 | /* 28 | * red-black trees properties: http://en.wikipedia.org/wiki/Rbtree 29 | * 30 | * 1) A node is either red or black 31 | * 2) The root is black 32 | * 3) All leaves (NULL) are black 33 | * 4) Both children of every red node are black 34 | * 5) Every simple path from root to leaves contains the same number 35 | * of black nodes. 36 | * 37 | * 4 and 5 give the O(log n) guarantee, since 4 implies you cannot have two 38 | * consecutive red nodes in a path and every red node is therefore followed by 39 | * a black. So if B is the number of black nodes on every simple path (as per 40 | * 5), then the longest possible path due to 4 is 2B. 41 | * 42 | * We shall indicate color with case, where black nodes are uppercase and red 43 | * nodes will be lowercase. Unknown color nodes shall be drawn as red within 44 | * parentheses and have some accompanying text comment. 45 | */ 46 | 47 | static inline void rb_set_black(struct rb_node *rb) 48 | { 49 | rb->__rb_parent_color |= RB_BLACK; 50 | } 51 | 52 | static inline struct rb_node *rb_red_parent(struct rb_node *red) 53 | { 54 | return (struct rb_node *)red->__rb_parent_color; 55 | } 56 | 57 | /* 58 | * Helper function for rotations: 59 | * - old's parent and color get assigned to new 60 | * - old gets assigned new as a parent and 'color' as a color. 61 | */ 62 | static inline void 63 | __rb_rotate_set_parents(struct rb_node *old, struct rb_node *new, 64 | struct rb_root *root, int color) 65 | { 66 | struct rb_node *parent = rb_parent(old); 67 | new->__rb_parent_color = old->__rb_parent_color; 68 | rb_set_parent_color(old, new, color); 69 | __rb_change_child(old, new, parent, root); 70 | } 71 | 72 | static inline void 73 | __rb_insert(struct rb_node *node, struct rb_root *root, 74 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) 75 | { 76 | struct rb_node *parent = rb_red_parent(node), *gparent, *tmp; 77 | 78 | while (true) { 79 | /* 80 | * Loop invariant: node is red 81 | * 82 | * If there is a black parent, we are done. 83 | * Otherwise, take some corrective action as we don't 84 | * want a red root or two consecutive red nodes. 85 | */ 86 | if (!parent) { 87 | rb_set_parent_color(node, NULL, RB_BLACK); 88 | break; 89 | } else if (rb_is_black(parent)) 90 | break; 91 | 92 | gparent = rb_red_parent(parent); 93 | 94 | tmp = gparent->rb_right; 95 | if (parent != tmp) { /* parent == gparent->rb_left */ 96 | if (tmp && rb_is_red(tmp)) { 97 | /* 98 | * Case 1 - color flips 99 | * 100 | * G g 101 | * / \ / \ 102 | * p u --> P U 103 | * / / 104 | * n n 105 | * 106 | * However, since g's parent might be red, and 107 | * 4) does not allow this, we need to recurse 108 | * at g. 109 | */ 110 | rb_set_parent_color(tmp, gparent, RB_BLACK); 111 | rb_set_parent_color(parent, gparent, RB_BLACK); 112 | node = gparent; 113 | parent = rb_parent(node); 114 | rb_set_parent_color(node, parent, RB_RED); 115 | continue; 116 | } 117 | 118 | tmp = parent->rb_right; 119 | if (node == tmp) { 120 | /* 121 | * Case 2 - left rotate at parent 122 | * 123 | * G G 124 | * / \ / \ 125 | * p U --> n U 126 | * \ / 127 | * n p 128 | * 129 | * This still leaves us in violation of 4), the 130 | * continuation into Case 3 will fix that. 131 | */ 132 | parent->rb_right = tmp = node->rb_left; 133 | node->rb_left = parent; 134 | if (tmp) 135 | rb_set_parent_color(tmp, parent, 136 | RB_BLACK); 137 | rb_set_parent_color(parent, node, RB_RED); 138 | augment_rotate(parent, node); 139 | parent = node; 140 | tmp = node->rb_right; 141 | } 142 | 143 | /* 144 | * Case 3 - right rotate at gparent 145 | * 146 | * G P 147 | * / \ / \ 148 | * p U --> n g 149 | * / \ 150 | * n U 151 | */ 152 | gparent->rb_left = tmp; /* == parent->rb_right */ 153 | parent->rb_right = gparent; 154 | if (tmp) 155 | rb_set_parent_color(tmp, gparent, RB_BLACK); 156 | __rb_rotate_set_parents(gparent, parent, root, RB_RED); 157 | augment_rotate(gparent, parent); 158 | break; 159 | } else { 160 | tmp = gparent->rb_left; 161 | if (tmp && rb_is_red(tmp)) { 162 | /* Case 1 - color flips */ 163 | rb_set_parent_color(tmp, gparent, RB_BLACK); 164 | rb_set_parent_color(parent, gparent, RB_BLACK); 165 | node = gparent; 166 | parent = rb_parent(node); 167 | rb_set_parent_color(node, parent, RB_RED); 168 | continue; 169 | } 170 | 171 | tmp = parent->rb_left; 172 | if (node == tmp) { 173 | /* Case 2 - right rotate at parent */ 174 | parent->rb_left = tmp = node->rb_right; 175 | node->rb_right = parent; 176 | if (tmp) 177 | rb_set_parent_color(tmp, parent, 178 | RB_BLACK); 179 | rb_set_parent_color(parent, node, RB_RED); 180 | augment_rotate(parent, node); 181 | parent = node; 182 | tmp = node->rb_left; 183 | } 184 | 185 | /* Case 3 - left rotate at gparent */ 186 | gparent->rb_right = tmp; /* == parent->rb_left */ 187 | parent->rb_left = gparent; 188 | if (tmp) 189 | rb_set_parent_color(tmp, gparent, RB_BLACK); 190 | __rb_rotate_set_parents(gparent, parent, root, RB_RED); 191 | augment_rotate(gparent, parent); 192 | break; 193 | } 194 | } 195 | } 196 | 197 | /* 198 | * Inline version for rb_erase() use - we want to be able to inline 199 | * and eliminate the dummy_rotate callback there 200 | */ 201 | static inline void 202 | ____rb_erase_color(struct rb_node *parent, struct rb_root *root, 203 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) 204 | { 205 | struct rb_node *node = NULL, *sibling, *tmp1, *tmp2; 206 | 207 | while (true) { 208 | /* 209 | * Loop invariants: 210 | * - node is black (or NULL on first iteration) 211 | * - node is not the root (parent is not NULL) 212 | * - All leaf paths going through parent and node have a 213 | * black node count that is 1 lower than other leaf paths. 214 | */ 215 | sibling = parent->rb_right; 216 | if (node != sibling) { /* node == parent->rb_left */ 217 | if (rb_is_red(sibling)) { 218 | /* 219 | * Case 1 - left rotate at parent 220 | * 221 | * P S 222 | * / \ / \ 223 | * N s --> p Sr 224 | * / \ / \ 225 | * Sl Sr N Sl 226 | */ 227 | parent->rb_right = tmp1 = sibling->rb_left; 228 | sibling->rb_left = parent; 229 | rb_set_parent_color(tmp1, parent, RB_BLACK); 230 | __rb_rotate_set_parents(parent, sibling, root, 231 | RB_RED); 232 | augment_rotate(parent, sibling); 233 | sibling = tmp1; 234 | } 235 | tmp1 = sibling->rb_right; 236 | if (!tmp1 || rb_is_black(tmp1)) { 237 | tmp2 = sibling->rb_left; 238 | if (!tmp2 || rb_is_black(tmp2)) { 239 | /* 240 | * Case 2 - sibling color flip 241 | * (p could be either color here) 242 | * 243 | * (p) (p) 244 | * / \ / \ 245 | * N S --> N s 246 | * / \ / \ 247 | * Sl Sr Sl Sr 248 | * 249 | * This leaves us violating 5) which 250 | * can be fixed by flipping p to black 251 | * if it was red, or by recursing at p. 252 | * p is red when coming from Case 1. 253 | */ 254 | rb_set_parent_color(sibling, parent, 255 | RB_RED); 256 | if (rb_is_red(parent)) 257 | rb_set_black(parent); 258 | else { 259 | node = parent; 260 | parent = rb_parent(node); 261 | if (parent) 262 | continue; 263 | } 264 | break; 265 | } 266 | /* 267 | * Case 3 - right rotate at sibling 268 | * (p could be either color here) 269 | * 270 | * (p) (p) 271 | * / \ / \ 272 | * N S --> N Sl 273 | * / \ \ 274 | * sl Sr s 275 | * \ 276 | * Sr 277 | */ 278 | sibling->rb_left = tmp1 = tmp2->rb_right; 279 | tmp2->rb_right = sibling; 280 | parent->rb_right = tmp2; 281 | if (tmp1) 282 | rb_set_parent_color(tmp1, sibling, 283 | RB_BLACK); 284 | augment_rotate(sibling, tmp2); 285 | tmp1 = sibling; 286 | sibling = tmp2; 287 | } 288 | /* 289 | * Case 4 - left rotate at parent + color flips 290 | * (p and sl could be either color here. 291 | * After rotation, p becomes black, s acquires 292 | * p's color, and sl keeps its color) 293 | * 294 | * (p) (s) 295 | * / \ / \ 296 | * N S --> P Sr 297 | * / \ / \ 298 | * (sl) sr N (sl) 299 | */ 300 | parent->rb_right = tmp2 = sibling->rb_left; 301 | sibling->rb_left = parent; 302 | rb_set_parent_color(tmp1, sibling, RB_BLACK); 303 | if (tmp2) 304 | rb_set_parent(tmp2, parent); 305 | __rb_rotate_set_parents(parent, sibling, root, 306 | RB_BLACK); 307 | augment_rotate(parent, sibling); 308 | break; 309 | } else { 310 | sibling = parent->rb_left; 311 | if (rb_is_red(sibling)) { 312 | /* Case 1 - right rotate at parent */ 313 | parent->rb_left = tmp1 = sibling->rb_right; 314 | sibling->rb_right = parent; 315 | rb_set_parent_color(tmp1, parent, RB_BLACK); 316 | __rb_rotate_set_parents(parent, sibling, root, 317 | RB_RED); 318 | augment_rotate(parent, sibling); 319 | sibling = tmp1; 320 | } 321 | tmp1 = sibling->rb_left; 322 | if (!tmp1 || rb_is_black(tmp1)) { 323 | tmp2 = sibling->rb_right; 324 | if (!tmp2 || rb_is_black(tmp2)) { 325 | /* Case 2 - sibling color flip */ 326 | rb_set_parent_color(sibling, parent, 327 | RB_RED); 328 | if (rb_is_red(parent)) 329 | rb_set_black(parent); 330 | else { 331 | node = parent; 332 | parent = rb_parent(node); 333 | if (parent) 334 | continue; 335 | } 336 | break; 337 | } 338 | /* Case 3 - right rotate at sibling */ 339 | sibling->rb_right = tmp1 = tmp2->rb_left; 340 | tmp2->rb_left = sibling; 341 | parent->rb_left = tmp2; 342 | if (tmp1) 343 | rb_set_parent_color(tmp1, sibling, 344 | RB_BLACK); 345 | augment_rotate(sibling, tmp2); 346 | tmp1 = sibling; 347 | sibling = tmp2; 348 | } 349 | /* Case 4 - left rotate at parent + color flips */ 350 | parent->rb_left = tmp2 = sibling->rb_right; 351 | sibling->rb_right = parent; 352 | rb_set_parent_color(tmp1, sibling, RB_BLACK); 353 | if (tmp2) 354 | rb_set_parent(tmp2, parent); 355 | __rb_rotate_set_parents(parent, sibling, root, 356 | RB_BLACK); 357 | augment_rotate(parent, sibling); 358 | break; 359 | } 360 | } 361 | } 362 | 363 | /* Non-inline version for rb_erase_augmented() use */ 364 | void __rb_erase_color(struct rb_node *parent, struct rb_root *root, 365 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) 366 | { 367 | ____rb_erase_color(parent, root, augment_rotate); 368 | } 369 | 370 | /* 371 | * Non-augmented rbtree manipulation functions. 372 | * 373 | * We use dummy augmented callbacks here, and have the compiler optimize them 374 | * out of the rb_insert_color() and rb_erase() function definitions. 375 | */ 376 | 377 | static inline void dummy_propagate(struct rb_node *node, struct rb_node *stop) {} 378 | static inline void dummy_copy(struct rb_node *old, struct rb_node *new) {} 379 | static inline void dummy_rotate(struct rb_node *old, struct rb_node *new) {} 380 | 381 | static const struct rb_augment_callbacks dummy_callbacks = { 382 | dummy_propagate, dummy_copy, dummy_rotate 383 | }; 384 | 385 | void rb_insert_color(struct rb_node *node, struct rb_root *root) 386 | { 387 | __rb_insert(node, root, dummy_rotate); 388 | } 389 | 390 | void rb_erase(struct rb_node *node, struct rb_root *root) 391 | { 392 | struct rb_node *rebalance; 393 | rebalance = __rb_erase_augmented(node, root, &dummy_callbacks); 394 | if (rebalance) 395 | ____rb_erase_color(rebalance, root, dummy_rotate); 396 | } 397 | 398 | /* 399 | * Augmented rbtree manipulation functions. 400 | * 401 | * This instantiates the same __always_inline functions as in the non-augmented 402 | * case, but this time with user-defined callbacks. 403 | */ 404 | 405 | void __rb_insert_augmented(struct rb_node *node, struct rb_root *root, 406 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) 407 | { 408 | __rb_insert(node, root, augment_rotate); 409 | } 410 | 411 | /* 412 | * This function returns the first node (in sort order) of the tree. 413 | */ 414 | struct rb_node *rb_first(const struct rb_root *root) 415 | { 416 | struct rb_node *n; 417 | 418 | n = root->rb_node; 419 | if (!n) 420 | return NULL; 421 | while (n->rb_left) 422 | n = n->rb_left; 423 | return n; 424 | } 425 | 426 | struct rb_node *rb_last(const struct rb_root *root) 427 | { 428 | struct rb_node *n; 429 | 430 | n = root->rb_node; 431 | if (!n) 432 | return NULL; 433 | while (n->rb_right) 434 | n = n->rb_right; 435 | return n; 436 | } 437 | 438 | struct rb_node *rb_next(const struct rb_node *node) 439 | { 440 | struct rb_node *parent; 441 | 442 | if (RB_EMPTY_NODE(node)) 443 | return NULL; 444 | 445 | /* 446 | * If we have a right-hand child, go down and then left as far 447 | * as we can. 448 | */ 449 | if (node->rb_right) { 450 | node = node->rb_right; 451 | while (node->rb_left) 452 | node=node->rb_left; 453 | return (struct rb_node *)node; 454 | } 455 | 456 | /* 457 | * No right-hand children. Everything down and left is smaller than us, 458 | * so any 'next' node must be in the general direction of our parent. 459 | * Go up the tree; any time the ancestor is a right-hand child of its 460 | * parent, keep going up. First time it's a left-hand child of its 461 | * parent, said parent is our 'next' node. 462 | */ 463 | while ((parent = rb_parent(node)) && node == parent->rb_right) 464 | node = parent; 465 | 466 | return parent; 467 | } 468 | 469 | struct rb_node *rb_prev(const struct rb_node *node) 470 | { 471 | struct rb_node *parent; 472 | 473 | if (RB_EMPTY_NODE(node)) 474 | return NULL; 475 | 476 | /* 477 | * If we have a left-hand child, go down and then right as far 478 | * as we can. 479 | */ 480 | if (node->rb_left) { 481 | node = node->rb_left; 482 | while (node->rb_right) 483 | node=node->rb_right; 484 | return (struct rb_node *)node; 485 | } 486 | 487 | /* 488 | * No left-hand children. Go up till we find an ancestor which 489 | * is a right-hand child of its parent. 490 | */ 491 | while ((parent = rb_parent(node)) && node == parent->rb_left) 492 | node = parent; 493 | 494 | return parent; 495 | } 496 | 497 | void rb_replace_node(struct rb_node *victim, struct rb_node *new, 498 | struct rb_root *root) 499 | { 500 | struct rb_node *parent = rb_parent(victim); 501 | 502 | /* Set the surrounding nodes to point to the replacement */ 503 | __rb_change_child(victim, new, parent, root); 504 | if (victim->rb_left) 505 | rb_set_parent(victim->rb_left, new); 506 | if (victim->rb_right) 507 | rb_set_parent(victim->rb_right, new); 508 | 509 | /* Copy the pointers/colour from the victim to the replacement */ 510 | *new = *victim; 511 | } 512 | 513 | static struct rb_node *rb_left_deepest_node(const struct rb_node *node) 514 | { 515 | for (;;) { 516 | if (node->rb_left) 517 | node = node->rb_left; 518 | else if (node->rb_right) 519 | node = node->rb_right; 520 | else 521 | return (struct rb_node *)node; 522 | } 523 | } 524 | 525 | struct rb_node *rb_next_postorder(const struct rb_node *node) 526 | { 527 | const struct rb_node *parent; 528 | if (!node) 529 | return NULL; 530 | parent = rb_parent(node); 531 | 532 | /* If we're sitting on node, we've already seen our children */ 533 | if (parent && node == parent->rb_left && parent->rb_right) { 534 | /* If we are the parent's left node, go to the parent's right 535 | * node then all the way down to the left */ 536 | return rb_left_deepest_node(parent->rb_right); 537 | } else 538 | /* Otherwise we are the parent's right node, and the parent 539 | * should be next */ 540 | return (struct rb_node *)parent; 541 | } 542 | 543 | struct rb_node *rb_first_postorder(const struct rb_root *root) 544 | { 545 | if (!root->rb_node) 546 | return NULL; 547 | 548 | return rb_left_deepest_node(root->rb_node); 549 | } 550 | -------------------------------------------------------------------------------- /common/rbtree.h: -------------------------------------------------------------------------------- 1 | /* 2 | Red Black Trees 3 | (C) 1999 Andrea Arcangeli 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | linux/include/linux/rbtree.h 20 | 21 | To use rbtrees you'll have to implement your own insert and search cores. 22 | This will avoid us to use callbacks and to drop drammatically performances. 23 | I know it's not the cleaner way, but in C (not in C++) to get 24 | performances and genericity... 25 | 26 | See Documentation/rbtree.txt for documentation and samples. 27 | */ 28 | 29 | #ifndef _LINUX_RBTREE_H 30 | #define _LINUX_RBTREE_H 31 | 32 | #include 33 | 34 | /** 35 | * container_of - cast a member of a structure out to the containing structure 36 | * @ptr: the pointer to the member. 37 | * @type: the type of the container struct this is embedded in. 38 | * @member: the name of the member within the struct. 39 | * 40 | */ 41 | #define container_of(ptr, type, member) ({ \ 42 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 43 | (type *)( (char *)__mptr - offsetof(type,member) );}) 44 | 45 | struct rb_node { 46 | unsigned long __rb_parent_color; 47 | struct rb_node *rb_right; 48 | struct rb_node *rb_left; 49 | } __attribute__((aligned(sizeof(long)))); 50 | /* The alignment might seem pointless, but allegedly CRIS needs it */ 51 | 52 | struct rb_root { 53 | struct rb_node *rb_node; 54 | }; 55 | 56 | 57 | #define rb_parent(r) ((struct rb_node *)((r)->__rb_parent_color & ~3)) 58 | 59 | #define RB_ROOT (struct rb_root) { NULL, } 60 | #define rb_entry(ptr, type, member) container_of(ptr, type, member) 61 | 62 | #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) 63 | 64 | /* 'empty' nodes are nodes that are known not to be inserted in an rbtree */ 65 | #define RB_EMPTY_NODE(node) \ 66 | ((node)->__rb_parent_color == (unsigned long)(node)) 67 | #define RB_CLEAR_NODE(node) \ 68 | ((node)->__rb_parent_color = (unsigned long)(node)) 69 | 70 | 71 | extern void rb_insert_color(struct rb_node *, struct rb_root *); 72 | extern void rb_erase(struct rb_node *, struct rb_root *); 73 | 74 | 75 | /* Find logical next and previous nodes in a tree */ 76 | extern struct rb_node *rb_next(const struct rb_node *); 77 | extern struct rb_node *rb_prev(const struct rb_node *); 78 | extern struct rb_node *rb_first(const struct rb_root *); 79 | extern struct rb_node *rb_last(const struct rb_root *); 80 | 81 | /* Postorder iteration - always visit the parent after its children */ 82 | extern struct rb_node *rb_first_postorder(const struct rb_root *); 83 | extern struct rb_node *rb_next_postorder(const struct rb_node *); 84 | 85 | /* Fast replacement of a single node without remove/rebalance/add/rebalance */ 86 | extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, 87 | struct rb_root *root); 88 | 89 | static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, 90 | struct rb_node ** rb_link) 91 | { 92 | node->__rb_parent_color = (unsigned long)parent; 93 | node->rb_left = node->rb_right = NULL; 94 | 95 | *rb_link = node; 96 | } 97 | 98 | #define rb_entry_safe(ptr, type, member) \ 99 | ({ typeof(ptr) ____ptr = (ptr); \ 100 | ____ptr ? rb_entry(____ptr, type, member) : NULL; \ 101 | }) 102 | 103 | /** 104 | * rbtree_postorder_for_each_entry_safe - iterate over rb_root in post order of 105 | * given type safe against removal of rb_node entry 106 | * 107 | * @pos: the 'type *' to use as a loop cursor. 108 | * @n: another 'type *' to use as temporary storage 109 | * @root: 'rb_root *' of the rbtree. 110 | * @field: the name of the rb_node field within 'type'. 111 | */ 112 | #define rbtree_postorder_for_each_entry_safe(pos, n, root, field) \ 113 | for (pos = rb_entry_safe(rb_first_postorder(root), typeof(*pos), field); \ 114 | pos && ({ n = rb_entry_safe(rb_next_postorder(&pos->field), \ 115 | typeof(*pos), field); 1; }); \ 116 | pos = n) 117 | 118 | #endif /* _LINUX_RBTREE_H */ 119 | -------------------------------------------------------------------------------- /common/rbtree_augmented.h: -------------------------------------------------------------------------------- 1 | /* 2 | Red Black Trees 3 | (C) 1999 Andrea Arcangeli 4 | (C) 2002 David Woodhouse 5 | (C) 2012 Michel Lespinasse 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | 21 | linux/include/linux/rbtree_augmented.h 22 | */ 23 | 24 | #ifndef _LINUX_RBTREE_AUGMENTED_H 25 | #define _LINUX_RBTREE_AUGMENTED_H 26 | 27 | #include 28 | #include "rbtree.h" 29 | 30 | /* 31 | * Please note - only struct rb_augment_callbacks and the prototypes for 32 | * rb_insert_augmented() and rb_erase_augmented() are intended to be public. 33 | * The rest are implementation details you are not expected to depend on. 34 | * 35 | * See Documentation/rbtree.txt for documentation and samples. 36 | */ 37 | 38 | struct rb_augment_callbacks { 39 | void (*propagate)(struct rb_node *node, struct rb_node *stop); 40 | void (*copy)(struct rb_node *old, struct rb_node *new); 41 | void (*rotate)(struct rb_node *old, struct rb_node *new); 42 | }; 43 | 44 | extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root, 45 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); 46 | /* 47 | * Fixup the rbtree and update the augmented information when rebalancing. 48 | * 49 | * On insertion, the user must update the augmented information on the path 50 | * leading to the inserted node, then call rb_link_node() as usual and 51 | * rb_augment_inserted() instead of the usual rb_insert_color() call. 52 | * If rb_augment_inserted() rebalances the rbtree, it will callback into 53 | * a user provided function to update the augmented information on the 54 | * affected subtrees. 55 | */ 56 | static inline void 57 | rb_insert_augmented(struct rb_node *node, struct rb_root *root, 58 | const struct rb_augment_callbacks *augment) 59 | { 60 | __rb_insert_augmented(node, root, augment->rotate); 61 | } 62 | 63 | #define RB_DECLARE_CALLBACKS(rbstatic, rbname, rbstruct, rbfield, \ 64 | rbtype, rbaugmented, rbcompute) \ 65 | static inline void \ 66 | rbname ## _propagate(struct rb_node *rb, struct rb_node *stop) \ 67 | { \ 68 | while (rb != stop) { \ 69 | rbstruct *node = rb_entry(rb, rbstruct, rbfield); \ 70 | rbtype augmented = rbcompute(node); \ 71 | if (node->rbaugmented == augmented) \ 72 | break; \ 73 | node->rbaugmented = augmented; \ 74 | rb = rb_parent(&node->rbfield); \ 75 | } \ 76 | } \ 77 | static inline void \ 78 | rbname ## _copy(struct rb_node *rb_old, struct rb_node *rb_new) \ 79 | { \ 80 | rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ 81 | rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ 82 | new->rbaugmented = old->rbaugmented; \ 83 | } \ 84 | static void \ 85 | rbname ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new) \ 86 | { \ 87 | rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ 88 | rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ 89 | new->rbaugmented = old->rbaugmented; \ 90 | old->rbaugmented = rbcompute(old); \ 91 | } \ 92 | rbstatic const struct rb_augment_callbacks rbname = { \ 93 | rbname ## _propagate, rbname ## _copy, rbname ## _rotate \ 94 | }; 95 | 96 | 97 | #define RB_RED 0 98 | #define RB_BLACK 1 99 | 100 | #define __rb_parent(pc) ((struct rb_node *)(pc & ~3)) 101 | 102 | #define __rb_color(pc) ((pc) & 1) 103 | #define __rb_is_black(pc) __rb_color(pc) 104 | #define __rb_is_red(pc) (!__rb_color(pc)) 105 | #define rb_color(rb) __rb_color((rb)->__rb_parent_color) 106 | #define rb_is_red(rb) __rb_is_red((rb)->__rb_parent_color) 107 | #define rb_is_black(rb) __rb_is_black((rb)->__rb_parent_color) 108 | 109 | static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) 110 | { 111 | rb->__rb_parent_color = rb_color(rb) | (unsigned long)p; 112 | } 113 | 114 | static inline void rb_set_parent_color(struct rb_node *rb, 115 | struct rb_node *p, int color) 116 | { 117 | rb->__rb_parent_color = (unsigned long)p | color; 118 | } 119 | 120 | static inline void 121 | __rb_change_child(struct rb_node *old, struct rb_node *new, 122 | struct rb_node *parent, struct rb_root *root) 123 | { 124 | if (parent) { 125 | if (parent->rb_left == old) 126 | parent->rb_left = new; 127 | else 128 | parent->rb_right = new; 129 | } else 130 | root->rb_node = new; 131 | } 132 | 133 | extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root, 134 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); 135 | 136 | static inline struct rb_node * 137 | __rb_erase_augmented(struct rb_node *node, struct rb_root *root, 138 | const struct rb_augment_callbacks *augment) 139 | { 140 | struct rb_node *child = node->rb_right, *tmp = node->rb_left; 141 | struct rb_node *parent, *rebalance; 142 | unsigned long pc; 143 | 144 | if (!tmp) { 145 | /* 146 | * Case 1: node to erase has no more than 1 child (easy!) 147 | * 148 | * Note that if there is one child it must be red due to 5) 149 | * and node must be black due to 4). We adjust colors locally 150 | * so as to bypass __rb_erase_color() later on. 151 | */ 152 | pc = node->__rb_parent_color; 153 | parent = __rb_parent(pc); 154 | __rb_change_child(node, child, parent, root); 155 | if (child) { 156 | child->__rb_parent_color = pc; 157 | rebalance = NULL; 158 | } else 159 | rebalance = __rb_is_black(pc) ? parent : NULL; 160 | tmp = parent; 161 | } else if (!child) { 162 | /* Still case 1, but this time the child is node->rb_left */ 163 | tmp->__rb_parent_color = pc = node->__rb_parent_color; 164 | parent = __rb_parent(pc); 165 | __rb_change_child(node, tmp, parent, root); 166 | rebalance = NULL; 167 | tmp = parent; 168 | } else { 169 | struct rb_node *successor = child, *child2; 170 | tmp = child->rb_left; 171 | if (!tmp) { 172 | /* 173 | * Case 2: node's successor is its right child 174 | * 175 | * (n) (s) 176 | * / \ / \ 177 | * (x) (s) -> (x) (c) 178 | * \ 179 | * (c) 180 | */ 181 | parent = successor; 182 | child2 = successor->rb_right; 183 | augment->copy(node, successor); 184 | } else { 185 | /* 186 | * Case 3: node's successor is leftmost under 187 | * node's right child subtree 188 | * 189 | * (n) (s) 190 | * / \ / \ 191 | * (x) (y) -> (x) (y) 192 | * / / 193 | * (p) (p) 194 | * / / 195 | * (s) (c) 196 | * \ 197 | * (c) 198 | */ 199 | do { 200 | parent = successor; 201 | successor = tmp; 202 | tmp = tmp->rb_left; 203 | } while (tmp); 204 | parent->rb_left = child2 = successor->rb_right; 205 | successor->rb_right = child; 206 | rb_set_parent(child, successor); 207 | augment->copy(node, successor); 208 | augment->propagate(parent, successor); 209 | } 210 | 211 | successor->rb_left = tmp = node->rb_left; 212 | rb_set_parent(tmp, successor); 213 | 214 | pc = node->__rb_parent_color; 215 | tmp = __rb_parent(pc); 216 | __rb_change_child(node, successor, tmp, root); 217 | if (child2) { 218 | successor->__rb_parent_color = pc; 219 | rb_set_parent_color(child2, parent, RB_BLACK); 220 | rebalance = NULL; 221 | } else { 222 | unsigned long pc2 = successor->__rb_parent_color; 223 | successor->__rb_parent_color = pc; 224 | rebalance = __rb_is_black(pc2) ? parent : NULL; 225 | } 226 | tmp = successor; 227 | } 228 | 229 | augment->propagate(tmp, NULL); 230 | return rebalance; 231 | } 232 | 233 | static inline void 234 | rb_erase_augmented(struct rb_node *node, struct rb_root *root, 235 | const struct rb_augment_callbacks *augment) 236 | { 237 | struct rb_node *rebalance = __rb_erase_augmented(node, root, augment); 238 | if (rebalance) 239 | __rb_erase_color(rebalance, root, augment->rotate); 240 | } 241 | 242 | #endif /* _LINUX_RBTREE_AUGMENTED_H */ 243 | -------------------------------------------------------------------------------- /common/rbtree_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "rbtree.h" 4 | 5 | 6 | struct fd_node { 7 | struct rb_node rb; 8 | int fd; 9 | }; 10 | 11 | int fd_insert(struct rb_root *root, struct fd_node *data) 12 | { 13 | struct rb_node **new = &(root->rb_node), *parent = NULL; 14 | 15 | /* Figure out where to put new node */ 16 | while (*new) { 17 | struct fd_node *this = container_of(*new, struct fd_node, rb); 18 | int result = data->fd - this->fd; 19 | 20 | parent = *new; 21 | if (result < 0) 22 | new = &((*new)->rb_left); 23 | else if (result > 0) 24 | new = &((*new)->rb_right); 25 | else 26 | return 0; 27 | } 28 | 29 | /* Add new node and rebalance tree. */ 30 | rb_link_node(&data->rb, parent, new); 31 | rb_insert_color(&data->rb, root); 32 | 33 | return 1; 34 | } 35 | 36 | struct fd_node * fd_search(struct rb_root *root, int fd) 37 | { 38 | struct rb_node *node = root->rb_node; 39 | 40 | while (node) { 41 | struct fd_node *data = container_of(node, struct fd_node, rb); 42 | int result = fd - data->fd; 43 | 44 | if (result < 0) 45 | node = node->rb_left; 46 | else if (result > 0) 47 | node = node->rb_right; 48 | else 49 | return data; 50 | } 51 | return NULL; 52 | } 53 | 54 | void fd_free(struct fd_node *node) { 55 | if (node) { 56 | free(node); 57 | node = NULL; 58 | } 59 | } 60 | 61 | void fd_delete(struct rb_root *root, struct fd_node *node) { 62 | if (node) { 63 | rb_erase(&node->rb, root); 64 | } 65 | } 66 | 67 | #define fd_entry_for_each(root, type) \ 68 | struct rb_node *node;\ 69 | for (node = rb_first(&root); node; node = rb_next(node))\ 70 | printf("fd=%d\n", ((type *)rb_entry(node, struct fd_node, rb))->fd); 71 | 72 | 73 | int main() 74 | { 75 | int i; 76 | struct rb_root fd_root = RB_ROOT; 77 | 78 | for (i = 0; i < 1024; i++) { 79 | struct fd_node *fd_ptr = (struct fd_node*)malloc(sizeof(struct fd_node)); 80 | fd_ptr->fd = rand() % 1024; 81 | fd_insert(&fd_root, fd_ptr); 82 | } 83 | 84 | { 85 | struct rb_node *node; 86 | for (node = rb_first(&fd_root); node; node = rb_next(node)) { 87 | struct fd_node *fdptr = rb_entry(node, struct fd_node, rb); 88 | printf("fd=%d\n", fdptr->fd); 89 | } 90 | } 91 | //fd_entry_for_each(fd_root, struct fd_node); 92 | //fd_delete(&fd_root, fd_ptr); 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /ev_demo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ev_loop.h" 3 | #include "ev_type.h" 4 | #include 5 | #include 6 | 7 | ev_loop_t * loop = NULL; 8 | 9 | void *cb_stdin1(ev_loop_t *loop, int fd, EV_TYPE events); 10 | void *cb_timer1(ev_loop_t *loop, struct ev_timer *timer); 11 | 12 | clock_t b; 13 | 14 | #define NUM 5000000 15 | int main() 16 | { 17 | int i; 18 | loop = ev_create_loop(); 19 | 20 | ev_io_init(loop, 100, 1); 21 | for (i=0; i<1000; i++) 22 | ev_io_register(loop, 0, EV_READ, cb_stdin1, NULL); 23 | 24 | ev_timer_init(loop, NUM); 25 | b = clock(); 26 | for (i=0; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "ev_type.h" 14 | #include "ev_loop.h" 15 | 16 | static int setnonblocking(int fd); 17 | static int ev_listen(int port); 18 | 19 | void *cb_accept(ev_loop_t *loop, int fd, EV_TYPE events); 20 | void *cb_parse_request(ev_loop_t *loop, int fd, EV_TYPE events); 21 | void *cb_do_response(ev_loop_t *loop, int fd, EV_TYPE events); 22 | 23 | 24 | int main(int argc, char **argv) { 25 | if (argc != 2) { 26 | printf("usage: ./ev_httpd port\n"); 27 | return -1; 28 | } 29 | int ret; 30 | ev_loop_t *loop; 31 | int listen_sock; 32 | 33 | listen_sock = ev_listen(atoi(argv[1])); 34 | if (listen_sock == -1) { 35 | return -1; 36 | } 37 | 38 | loop = ev_create_loop(); 39 | ev_io_init(loop, 1024, 0); 40 | ret = ev_io_register(loop, listen_sock, EV_READ, cb_accept, NULL); 41 | if (ret == -1) { 42 | fprintf(stderr, "register listen sock error\n"); 43 | return -1; 44 | } 45 | printf("ev_httpd started successfully!\n"); 46 | ev_run_loop(loop); 47 | return 0; 48 | } 49 | void *cb_accept(ev_loop_t *loop, int fd, EV_TYPE events) { 50 | struct sockaddr_in client_sock; 51 | socklen_t len = sizeof(client_sock); 52 | int conn_fd; 53 | while ((conn_fd = accept(fd, (struct sockaddr *)&client_sock, &len)) > 0) { 54 | /*limit the number of connections*/ 55 | if (conn_fd >= loop->maxevent) { 56 | fprintf(stderr, "Warn: too many connections come, \ 57 | exceeds the maximum num of the configuration!\n"); 58 | close(conn_fd); 59 | return NULL; 60 | } 61 | 62 | setnonblocking(conn_fd); 63 | 64 | int ret = ev_io_register(loop, conn_fd, EV_READ, cb_parse_request, NULL); 65 | if (ret == -1) { 66 | fprintf(stderr, "ev io_register err in cd_accept()\n"); 67 | close(conn_fd); 68 | return NULL; 69 | } 70 | } 71 | if (-1 == conn_fd) { 72 | if (errno != EAGAIN) { 73 | fprintf(stderr, "accpet err: %s\n", strerror(errno)); 74 | return NULL; 75 | } 76 | } 77 | return NULL; 78 | } 79 | 80 | void *cb_parse_request(ev_loop_t *loop, int fd, EV_TYPE events) { 81 | //printf("in read\n"); 82 | char tmp[1024]; 83 | while(read(fd, tmp, 1024) > 0); 84 | int ret; 85 | ret = ev_io_stop(loop, fd, EV_READ); 86 | ret = ev_io_register(loop, fd, EV_WRITE, cb_do_response, NULL); 87 | if (ret == -1) { 88 | close(fd); 89 | } 90 | return NULL; 91 | } 92 | #define OUTPUT_STRING "hello evlib!" 93 | 94 | void *cb_do_response(ev_loop_t *loop, int fd, EV_TYPE events) { 95 | //printf("in write\n"); 96 | write(fd, OUTPUT_STRING, strlen(OUTPUT_STRING)); 97 | ev_io_unregister(loop, fd); 98 | close(fd); 99 | return NULL; 100 | } 101 | 102 | static 103 | int ev_listen(int port) { 104 | signal(SIGPIPE, SIG_IGN); 105 | struct sockaddr_in server_addr; 106 | int listen_sock; 107 | 108 | listen_sock = socket(AF_INET, SOCK_STREAM, 0); 109 | if (-1 == listen_sock) { 110 | fprintf(stderr, "create sock err: %s\n", strerror(errno)); 111 | return -1; 112 | } 113 | 114 | memset(&server_addr, 0, sizeof(server_addr)); 115 | 116 | server_addr.sin_port = htons(port); 117 | server_addr.sin_family = AF_INET; 118 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 119 | 120 | int ret; 121 | ret = bind(listen_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)); 122 | if (-1 == ret) { 123 | fprintf(stderr, "bind err: %s\n", strerror(errno)); 124 | return -1; 125 | } 126 | 127 | setnonblocking(listen_sock); 128 | 129 | int reuse = 1; 130 | setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); 131 | 132 | if (-1 == listen(listen_sock, SOMAXCONN)) { 133 | fprintf(stderr, "listen err: %s\n", strerror(errno)); 134 | return -1; 135 | } 136 | return listen_sock; 137 | } 138 | 139 | static 140 | int setnonblocking(int fd) { 141 | int flags; 142 | if (-1 == (flags = fcntl(fd, F_GETFL, 0))) { 143 | perror("setnonblocking error"); 144 | return -1; 145 | } 146 | return fcntl(fd, F_SETFL, flags | O_NONBLOCK); 147 | } 148 | 149 | 150 | -------------------------------------------------------------------------------- /ev_io.c: -------------------------------------------------------------------------------- 1 | #include "ev_loop.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #define MINEVENTNUMBER 1024 16 | 17 | int ev_io_init(ev_loop_t *loop, int max_ev_num, int etmodel) { 18 | /* set a default minumum num of evnets*/ 19 | if (max_ev_num < MINEVENTNUMBER) { 20 | max_ev_num = MINEVENTNUMBER; 21 | } 22 | loop->maxevent = max_ev_num; 23 | loop->io_cnt = 0; 24 | loop->etmodel = etmodel; 25 | loop->events = (struct epoll_event *)malloc(max_ev_num * sizeof(struct epoll_event)); 26 | if (loop->events == NULL) { 27 | fprintf(stderr, "No enough memory for loop->events\n"); 28 | return -1; 29 | } 30 | 31 | loop->iomap = (ev_io_t *)malloc(max_ev_num * sizeof(ev_io_t)); 32 | if (loop->iomap == NULL) { 33 | fprintf(stderr, "No enough memory for loop->iomap\n"); 34 | return -1; 35 | } 36 | int i; 37 | for (i = 0; i < max_ev_num; i++) { 38 | loop->iomap[i].active = 0; 39 | loop->iomap[i].events = 0; 40 | loop->iomap[i].cb_read = NULL; 41 | loop->iomap[i].cb_write = NULL; 42 | loop->iomap[i].ptr = NULL; 43 | } 44 | return 0; 45 | } 46 | 47 | int ev_io_register(ev_loop_t* loop, int fd, EV_TYPE events, cb_io_t cb, void *ptr) { 48 | if (fd >= loop->maxevent) { 49 | return -1; 50 | } 51 | if (!(events & EV_READ || events & EV_WRITE)) { 52 | fprintf(stderr, "invalid events\n"); 53 | return -1; 54 | } 55 | if (fd < 0) { 56 | fprintf(stderr, "invalid fd:%d\n", fd); 57 | return -1; 58 | } 59 | if (ptr != NULL) { 60 | loop->iomap[fd].ptr = ptr; 61 | } 62 | /* events registerd already, just change the cb */ 63 | if ((loop->iomap[fd].events & events) == events) { 64 | if (loop->iomap[fd].events & EV_READ) { 65 | loop->iomap[fd].cb_read = cb; 66 | } 67 | if (loop->iomap[fd].events & EV_WRITE) { 68 | loop->iomap[fd].cb_write = cb; 69 | } 70 | } 71 | /* new events going to be added */ 72 | else { 73 | if (EV_READ & events) { 74 | loop->iomap[fd].cb_read = cb; 75 | } 76 | if (EV_WRITE & events) { 77 | loop->iomap[fd].cb_write = cb; 78 | } 79 | loop->iomap[fd].events |= events; 80 | 81 | struct epoll_event ev; 82 | ev.events = loop->iomap[fd].events; 83 | if (loop->etmodel) { 84 | ev.events |= EPOLLET; 85 | } 86 | ev.data.fd = fd; 87 | 88 | if(loop->iomap[fd].active) {/*mod*/ 89 | if(-1 == epoll_ctl(loop->epfd, EPOLL_CTL_MOD, fd, &ev)) { 90 | fprintf(stderr, "ERROR: epoll_ctl mod in ev_register: %s\n", strerror(errno)); 91 | ev_io_clear(loop, fd); 92 | return -1; 93 | } 94 | } 95 | else {/*add*/ 96 | if(-1 == epoll_ctl(loop->epfd, EPOLL_CTL_ADD, fd, &ev)) { 97 | fprintf(stderr, "ERROR: epoll_ctl add in ev_register: %s\n", strerror(errno)); 98 | ev_io_unregister(loop, fd); 99 | return -1; 100 | } 101 | loop->io_cnt++; 102 | } 103 | } 104 | loop->iomap[fd].active = 1; 105 | return 0; 106 | } 107 | 108 | int ev_io_unregister(ev_loop_t* loop, int fd) { 109 | struct epoll_event ev; 110 | if (-1 == epoll_ctl(loop->epfd, EPOLL_CTL_DEL, fd, &ev)) { 111 | fprintf(stderr, "ERROR: epoll_ctl del in ev_unregister: %s\n", strerror(errno)); 112 | ev_io_clear(loop, fd); 113 | return -1; 114 | } 115 | ev_io_clear(loop, fd); 116 | return 0; 117 | } 118 | 119 | int ev_io_stop(ev_loop_t* loop, int fd, EV_TYPE events) { 120 | if (loop->iomap[fd].active && (loop->iomap[fd].events & events)) { 121 | loop->iomap[fd].events &= (~events); 122 | struct epoll_event ev; 123 | ev.events = loop->iomap[fd].events; 124 | if (loop->etmodel) { 125 | ev.events |= EPOLLET; 126 | } 127 | ev.data.fd = fd; 128 | 129 | if (-1 == epoll_ctl(loop->epfd, EPOLL_CTL_MOD, fd, &ev)) { 130 | fprintf(stderr, "ERROR: epoll_ctl mod in ev_stop: %s\n", strerror(errno)); 131 | ev_io_clear(loop, fd); 132 | return -1; 133 | } 134 | } 135 | return 0; 136 | } 137 | 138 | 139 | int ev_io_clear(ev_loop_t *loop, int fd) { 140 | loop->io_cnt--; 141 | loop->iomap[fd].active = 0; 142 | loop->iomap[fd].cb_read = NULL; 143 | loop->iomap[fd].cb_write = NULL; 144 | loop->iomap[fd].ptr = NULL; 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /ev_loop.c: -------------------------------------------------------------------------------- 1 | #include "ev_type.h" 2 | #include "ev_loop.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | ev_loop_t * ev_create_loop() { 14 | ev_loop_t *loop; 15 | loop = (ev_loop_t *)malloc(sizeof(ev_loop_t)); 16 | 17 | loop->epfd = epoll_create1(0); 18 | if (loop->epfd == -1) { 19 | fprintf(stderr, "create epoll error:%s\n", strerror(errno)); 20 | return NULL; 21 | } 22 | return loop; 23 | } 24 | 25 | int ev_run_loop(ev_loop_t* loop) { 26 | while (1) { 27 | int num; 28 | num = epoll_wait(loop->epfd, loop->events, loop->maxevent, -1); 29 | if (num == -1) { 30 | /* fix gbd can not run */ 31 | if (errno == EINTR) 32 | continue; 33 | fprintf(stderr, "ERROR: epoll wait error: %s\n", strerror(errno)); 34 | return -1; 35 | } 36 | int i; 37 | for (i = 0; i < num; i++) { 38 | int fd = loop->events[i].data.fd; 39 | ev_io_t io_record = loop->iomap[fd]; 40 | 41 | if (EV_READ & loop->events[i].events) { 42 | if (io_record.cb_read != NULL) 43 | (*(io_record.cb_read))(loop, fd, EV_READ); 44 | } 45 | /*pre-step may have unregisterd the fd, make sure the fd is active!*/ 46 | if ((EV_WRITE & loop->events[i].events) && io_record.active) { 47 | if (io_record.cb_write != NULL) 48 | (*(io_record.cb_write))(loop, fd, EV_WRITE); 49 | } 50 | } 51 | } 52 | return 0; 53 | } -------------------------------------------------------------------------------- /ev_loop.h: -------------------------------------------------------------------------------- 1 | #ifndef _EV_LOOP_H 2 | #define _EV_LOOP_H 3 | 4 | #include "ev_type.h" 5 | /* main loop */ 6 | extern ev_loop_t* ev_create_loop(); 7 | extern int ev_run_loop(ev_loop_t* loop); 8 | 9 | /* io event */ 10 | extern int ev_io_init(ev_loop_t *loop, int max_ev_num, int etmodel); 11 | extern int ev_io_register(ev_loop_t* loop, int fd, EV_TYPE events, cb_io_t cb, void *ptr); 12 | extern int ev_io_unregister(ev_loop_t* loop, int fd); 13 | extern int ev_io_stop(ev_loop_t* loop, int fd, EV_TYPE events); 14 | extern int ev_io_clear(ev_loop_t* loop, int fd); 15 | 16 | /* timer event */ 17 | extern int ev_timer_init(ev_loop_t *loop, int capacity); 18 | extern int ev_timer_register(ev_loop_t *loop, double timeout, cb_timer_t cb, uint8_t repeat, void *ptr); 19 | extern int ev_timer_unregister(ev_loop_t *loop, ev_timer_t *timer); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /ev_timer.c: -------------------------------------------------------------------------------- 1 | #include "ev_type.h" 2 | #include "ev_loop.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define FOURTH_MIN_HEAP 14 | 15 | #define RSHIFT(x) ((x) >> 1) 16 | #define LSHIFT(x) ((x) << 1) 17 | //#define RCHILD(x) (LSHIFT(x)|1) 18 | 19 | #ifdef FOURTH_MIN_HEAP 20 | #define LCHILD(x) ((x) * 4 - 2) 21 | #define PARENT(x) (((x) + 2) / 4) 22 | #else 23 | #define LCHILD(x) LSHIFT(x) 24 | #define PARENT(x) (RSHIFT(x)) 25 | #endif 26 | 27 | #define ONESECOND 1000000000 //in nanosecond 28 | 29 | static 30 | int timer_cmp_lt(struct timespec ts1, struct timespec ts2) { 31 | if (ts1.tv_sec > ts2.tv_sec || 32 | (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec >= ts2.tv_nsec)) { 33 | return 0; 34 | } 35 | return 1; 36 | } 37 | 38 | static 39 | void heap_percolate_up(ev_timer_t **heap, int pos) { 40 | ev_timer_t *timer = heap[pos]; 41 | while ((pos > 1) && (timer_cmp_lt(timer->ts, heap[PARENT(pos)]->ts))) { 42 | heap[pos] = heap[PARENT(pos)]; 43 | pos = PARENT(pos); 44 | } 45 | heap[pos] = timer; 46 | } 47 | 48 | static 49 | void heap_percolate_down(ev_timer_t **heap, int pos, int heap_size) { 50 | ev_timer_t *timer = heap[pos]; 51 | while (LCHILD(pos) <= heap_size) { 52 | int s_pos = LCHILD(pos); 53 | #ifdef FOURTH_MIN_HEAP 54 | int cnt = 4; 55 | #else 56 | int cnt = 2; 57 | #endif 58 | /* right child exist and right is smaller */ 59 | int i = 1; 60 | for (; i < cnt; i++) { 61 | if (s_pos + 1 <= heap_size && timer_cmp_lt(heap[s_pos + 1]->ts, heap[s_pos]->ts)) { 62 | s_pos++; 63 | } 64 | } 65 | 66 | if (timer_cmp_lt(timer->ts, heap[s_pos]->ts)) { 67 | break; 68 | } 69 | heap[pos] = heap[s_pos]; 70 | pos = s_pos; 71 | } 72 | heap[pos] = timer; 73 | } 74 | 75 | static 76 | void heap_add(ev_loop_t *loop, ev_timer_t *timer) { 77 | loop->heap[++(loop->heap_size)] = timer; 78 | heap_percolate_up(loop->heap, loop->heap_size); 79 | } 80 | 81 | /* timeout --> ts, which is the expired time */ 82 | static 83 | struct timespec double2timespec(double timeout) { 84 | long long int sec = (long long int)timeout; 85 | long long int nsec = (long long int)((timeout - (double)sec) * ONESECOND); 86 | 87 | struct timespec ts; 88 | clock_gettime(CLOCK_MONOTONIC, &ts); 89 | ts.tv_sec += sec; 90 | ts.tv_nsec += nsec; 91 | if (ts.tv_nsec >= ONESECOND) { 92 | ts.tv_nsec %= ONESECOND; 93 | ts.tv_sec++; 94 | } 95 | return ts; 96 | } 97 | 98 | static 99 | ev_timer_t* heap_top(ev_timer_t **heap) { 100 | return heap[1]; 101 | } 102 | 103 | static 104 | void heap_pop(ev_loop_t *loop) { 105 | if (loop->heap_size < 1) 106 | return; 107 | free(loop->heap[1]); 108 | loop->heap[1] = loop->heap[loop->heap_size]; 109 | loop->heap[loop->heap_size] = NULL; 110 | loop->heap_size--; 111 | heap_percolate_down(loop->heap, 1, loop->heap_size); 112 | } 113 | 114 | /* get next timeout */ 115 | static 116 | struct timespec get_next_ts(ev_loop_t *loop) { 117 | struct timespec ts; 118 | clock_gettime(CLOCK_MONOTONIC, &ts); 119 | /* process timeout events*/ 120 | while (heap_top(loop->heap) != NULL && !timer_cmp_lt(ts, heap_top(loop->heap)->ts)) { 121 | ////////////////////////////////////////// 122 | //heap != null, and delete all the cb==null timer in the head 123 | int bcontinue = 0; 124 | while (heap_top(loop->heap) != NULL && heap_top(loop->heap)->cb == NULL) { 125 | heap_pop(loop); 126 | bcontinue = 1; 127 | } 128 | if (bcontinue) { 129 | continue; 130 | } 131 | /* callback function */ 132 | (*(heap_top(loop->heap)->cb))(loop, heap_top(loop->heap)); 133 | 134 | if (!heap_top(loop->heap)->repeat) { 135 | heap_pop(loop); 136 | } 137 | else { 138 | heap_top(loop->heap)->ts = double2timespec(heap_top(loop->heap)->timeout); 139 | heap_percolate_down(loop->heap, 1, loop->heap_size); 140 | } 141 | /* important: update the current time, because you */ 142 | /* never know how long the callback func costs */ 143 | clock_gettime(CLOCK_MONOTONIC, &ts); 144 | } 145 | 146 | /* set to 0 to disarm the timer*/ 147 | if (heap_top(loop->heap) == NULL) { 148 | ts.tv_sec = 0; 149 | ts.tv_nsec = 0; 150 | return ts; 151 | } 152 | 153 | #ifdef EV_TEST 154 | printf(".............. *****.*********\n"); 155 | printf("after heap:... %ld.%ld\n", heap_top(loop->heap)->ts.tv_sec, heap_top(loop->heap)->ts.tv_nsec); 156 | printf("after ts:... %ld.%ld\n", ts.tv_sec, ts.tv_nsec); 157 | #endif 158 | 159 | long int sec_tmp = heap_top(loop->heap)->ts.tv_sec; 160 | long int nsec_tmp = heap_top(loop->heap)->ts.tv_nsec; 161 | 162 | if (ts.tv_nsec > heap_top(loop->heap)->ts.tv_nsec) { 163 | sec_tmp--; 164 | nsec_tmp += ONESECOND; 165 | } 166 | ts.tv_sec = sec_tmp - ts.tv_sec; 167 | ts.tv_nsec = nsec_tmp - ts.tv_nsec; 168 | 169 | return ts; 170 | } 171 | 172 | static 173 | void* cb_check_timer(ev_loop_t *loop, int tfd, EV_TYPE events) { 174 | uint64_t data; 175 | read(loop->timer_fd, &data, 8); 176 | 177 | struct timespec ts; 178 | ts = get_next_ts(loop); 179 | struct itimerspec newValue; 180 | bzero(&newValue, sizeof(newValue)); 181 | newValue.it_value = ts; 182 | 183 | int ret; 184 | ret = timerfd_settime(loop->timer_fd, 0, &newValue, NULL); 185 | if (ret == -1) { 186 | printf("ERROR: timerfd_settime err:%s\n", strerror(errno)); 187 | } 188 | return NULL; 189 | } 190 | 191 | 192 | /////////////////////////////////////////////////////////////////// 193 | 194 | int ev_timer_init(ev_loop_t *loop, int capacity) { 195 | loop->heap = (ev_timer_t**)malloc((capacity + 1)*sizeof(ev_timer_t*)); 196 | if (loop->heap == NULL) { 197 | fprintf(stderr, "ERROR: no enough memory!\n"); 198 | return -1; 199 | } 200 | int i; 201 | for (i = 0; i <= capacity; i++) { 202 | loop->heap[i] = NULL; 203 | } 204 | loop->heap_size = 0; 205 | loop->heap_capacity = capacity; 206 | 207 | 208 | if ((loop->timer_fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) { 209 | fprintf(stderr, "ERROR: init timerfd error\n"); 210 | return -1; 211 | } 212 | 213 | struct itimerspec newValue; 214 | bzero(&newValue, sizeof(newValue)); 215 | struct timespec ts; 216 | ts.tv_sec = 0; 217 | ts.tv_nsec = 0; 218 | newValue.it_value = ts; 219 | if (timerfd_settime(loop->timer_fd, 0, &newValue, NULL) != 0) { 220 | fprintf(stderr, "ERROR: timerfd_settime error: %s\n", strerror(errno)); 221 | return -1; 222 | } 223 | return ev_io_register(loop, loop->timer_fd, EV_READ, cb_check_timer, NULL); 224 | } 225 | 226 | int ev_timer_register(ev_loop_t *loop, double timeout, cb_timer_t cb, uint8_t repeat, void *ptr) { 227 | if (loop->heap_size >= loop->heap_capacity) { 228 | ev_timer_t **temp = (ev_timer_t **)malloc((2 * (loop->heap_capacity) + 1)*sizeof(ev_timer_t *)); 229 | if (temp == NULL) { 230 | fprintf(stderr, "ERROR: in ev_timer_register when malloc:%s\n", strerror(errno)); 231 | return -1; 232 | } 233 | int i; 234 | for (i = 0; i < 2 * (loop->heap_capacity) + 1; i++) { 235 | temp[i] = NULL; 236 | } 237 | loop->heap_capacity *= 2; 238 | for (i = 0; i <= loop->heap_size; i++) { 239 | temp[i] = loop->heap[i]; 240 | } 241 | free(loop->heap); 242 | loop->heap = temp; 243 | } 244 | 245 | ev_timer_t *timer = (ev_timer_t*)malloc(sizeof(ev_timer_t)); 246 | if (timer == NULL) { 247 | fprintf(stderr, "ERROR: malloc error:%s\n", strerror(errno)); 248 | return -1; 249 | } 250 | struct timespec ts; 251 | ts = double2timespec(timeout); 252 | 253 | timer->timeout = timeout; 254 | timer->ts = ts; 255 | timer->cb = cb; 256 | timer->repeat = repeat; 257 | timer->ptr = ptr; 258 | 259 | heap_add(loop, timer); 260 | 261 | /* two special conditions which need to settime */ 262 | /* 1. first timer event */ 263 | /* 2. the newly add timer is the new heap top */ 264 | /* that means new's ts < old heap top's ts */ 265 | if (loop->heap_size == 1 || heap_top(loop->heap) == timer) { 266 | ts = get_next_ts(loop); 267 | struct itimerspec newValue; 268 | bzero(&newValue, sizeof(newValue)); 269 | newValue.it_value = ts; 270 | 271 | if (timerfd_settime(loop->timer_fd, 0, &newValue, NULL) != 0) { 272 | fprintf(stderr, "ERROR: timerfd_settime error: %s\n", strerror(errno)); 273 | return -1; 274 | } 275 | } 276 | 277 | return 0; 278 | } 279 | int ev_timer_unregister(ev_loop_t *loop, ev_timer_t *timer) { 280 | /* just set cb = NULL*/ 281 | timer->cb = NULL; 282 | return 0; 283 | } 284 | 285 | -------------------------------------------------------------------------------- /ev_type.h: -------------------------------------------------------------------------------- 1 | #ifndef _EV_TYPE_H 2 | #define _EV_TYPE_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | #define EV_TYPE __uint32_t 9 | 10 | /* forward declaration */ 11 | struct ev_timer; 12 | struct ev_io; 13 | 14 | enum { 15 | EV_READ = EPOLLIN, 16 | EV_WRITE = EPOLLOUT 17 | }; 18 | 19 | /* main loop */ 20 | typedef struct ev_loop { 21 | /* io */ 22 | int epfd; 23 | int maxevent; 24 | int io_cnt; 25 | int etmodel; 26 | struct epoll_event *events; 27 | struct ev_io *iomap; 28 | 29 | /* timer */ 30 | struct ev_timer **heap; 31 | int heap_size; 32 | int heap_capacity; 33 | int timer_fd; 34 | } ev_loop_t; 35 | 36 | 37 | /* io */ 38 | typedef void* (*cb_io_t) (ev_loop_t *loop, int fd, EV_TYPE events); 39 | 40 | typedef struct ev_io { 41 | int active; 42 | 43 | EV_TYPE events; /* EV_READ / EV_WRITE*/ 44 | cb_io_t cb_read; /* EV_READ callback function */ 45 | cb_io_t cb_write; /* EV_WRITE callback function */ 46 | 47 | /*for custom use*/ 48 | void *ptr; 49 | } ev_io_t; 50 | 51 | 52 | /* timer */ 53 | typedef void* (*cb_timer_t) (ev_loop_t *loop, struct ev_timer *timer); 54 | 55 | typedef struct ev_timer { 56 | uint8_t repeat; /* do once or forever*/ 57 | double timeout; /* e.g. 9.1 => 9.1 s*/ 58 | struct timespec ts; /* timeout time in timespect type*/ 59 | cb_timer_t cb; /* callback function*/ 60 | 61 | void * ptr; /* for custom use*/ 62 | } ev_timer_t; 63 | 64 | 65 | 66 | #endif 67 | 68 | 69 | --------------------------------------------------------------------------------