├── .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 |
--------------------------------------------------------------------------------