logwang 4 years ago
parent
commit
a9643ea85c
  1. 7
      .gitignore
  2. BIN
      F-Stack.png
  3. 216
      LICENSE
  4. 106
      README.md
  5. 95
      app/micro_thread/Makefile
  6. 157
      app/micro_thread/arch_ctx.S
  7. 102
      app/micro_thread/echo.cpp
  8. 561
      app/micro_thread/epoll_proxy.cpp.bak
  9. 434
      app/micro_thread/epoll_proxy.h.bak
  10. 7
      app/micro_thread/f-stack.pc
  11. 222
      app/micro_thread/ff_hook.cpp
  12. 56
      app/micro_thread/ff_hook.h
  13. 290
      app/micro_thread/hash_list.h
  14. 441
      app/micro_thread/heap.h
  15. 115
      app/micro_thread/heap_timer.cpp
  16. 131
      app/micro_thread/heap_timer.h
  17. 561
      app/micro_thread/kqueue_proxy.cpp
  18. 320
      app/micro_thread/kqueue_proxy.h
  19. 1673
      app/micro_thread/micro_thread.cpp
  20. 925
      app/micro_thread/micro_thread.h
  21. 255
      app/micro_thread/mt_action.cpp
  22. 327
      app/micro_thread/mt_action.h
  23. 1329
      app/micro_thread/mt_api.cpp
  24. 410
      app/micro_thread/mt_api.h
  25. 869
      app/micro_thread/mt_cache.cpp
  26. 298
      app/micro_thread/mt_cache.h
  27. 528
      app/micro_thread/mt_concurrent.cpp
  28. 103
      app/micro_thread/mt_concurrent.h
  29. 921
      app/micro_thread/mt_connection.cpp
  30. 563
      app/micro_thread/mt_connection.h
  31. 37
      app/micro_thread/mt_incl.h
  32. 159
      app/micro_thread/mt_mbuf_pool.cpp
  33. 304
      app/micro_thread/mt_mbuf_pool.h
  34. 54
      app/micro_thread/mt_msg.h
  35. 1987
      app/micro_thread/mt_net.cpp
  36. 718
      app/micro_thread/mt_net.h
  37. 123
      app/micro_thread/mt_net_api.h
  38. 571
      app/micro_thread/mt_notify.cpp
  39. 568
      app/micro_thread/mt_notify.h
  40. 251
      app/micro_thread/mt_self_echo.cpp
  41. 142
      app/micro_thread/mt_session.cpp
  42. 187
      app/micro_thread/mt_session.h
  43. 413
      app/micro_thread/mt_sys_hook.cpp
  44. 130
      app/micro_thread/mt_sys_hook.h
  45. 41
      app/micro_thread/mt_version.h
  46. 6606
      app/micro_thread/valgrind/valgrind.h
  47. 7739
      app/nginx-1.11.10/CHANGES
  48. 7872
      app/nginx-1.11.10/CHANGES.ru
  49. 26
      app/nginx-1.11.10/LICENSE
  50. 3
      app/nginx-1.11.10/README
  51. 14
      app/nginx-1.11.10/auto/cc/acc
  52. 72
      app/nginx-1.11.10/auto/cc/bcc
  53. 46
      app/nginx-1.11.10/auto/cc/ccc
  54. 98
      app/nginx-1.11.10/auto/cc/clang
  55. 250
      app/nginx-1.11.10/auto/cc/conf
  56. 178
      app/nginx-1.11.10/auto/cc/gcc
  57. 117
      app/nginx-1.11.10/auto/cc/icc
  58. 157
      app/nginx-1.11.10/auto/cc/msvc
  59. 66
      app/nginx-1.11.10/auto/cc/name
  60. 104
      app/nginx-1.11.10/auto/cc/owc
  61. 160
      app/nginx-1.11.10/auto/cc/sunc
  62. 12
      app/nginx-1.11.10/auto/define
  63. 50
      app/nginx-1.11.10/auto/endianness
  64. 123
      app/nginx-1.11.10/auto/feature
  65. 12
      app/nginx-1.11.10/auto/have
  66. 12
      app/nginx-1.11.10/auto/have_headers
  67. 13
      app/nginx-1.11.10/auto/headers
  68. 58
      app/nginx-1.11.10/auto/include
  69. 51
      app/nginx-1.11.10/auto/init
  70. 218
      app/nginx-1.11.10/auto/install
  71. 54
      app/nginx-1.11.10/auto/lib/conf
  72. 97
      app/nginx-1.11.10/auto/lib/geoip/conf
  73. 61
      app/nginx-1.11.10/auto/lib/google-perftools/conf
  74. 43
      app/nginx-1.11.10/auto/lib/libatomic/conf
  75. 16
      app/nginx-1.11.10/auto/lib/libatomic/make
  76. 93
      app/nginx-1.11.10/auto/lib/libgd/conf
  77. 165
      app/nginx-1.11.10/auto/lib/libxslt/conf
  78. 24
      app/nginx-1.11.10/auto/lib/make
  79. 135
      app/nginx-1.11.10/auto/lib/openssl/conf
  80. 62
      app/nginx-1.11.10/auto/lib/openssl/make
  81. 18
      app/nginx-1.11.10/auto/lib/openssl/makefile.bcc
  82. 21
      app/nginx-1.11.10/auto/lib/openssl/makefile.msvc
  83. 203
      app/nginx-1.11.10/auto/lib/pcre/conf
  84. 64
      app/nginx-1.11.10/auto/lib/pcre/make
  85. 27
      app/nginx-1.11.10/auto/lib/pcre/makefile.bcc
  86. 23
      app/nginx-1.11.10/auto/lib/pcre/makefile.msvc
  87. 25
      app/nginx-1.11.10/auto/lib/pcre/makefile.owc
  88. 83
      app/nginx-1.11.10/auto/lib/perl/conf
  89. 46
      app/nginx-1.11.10/auto/lib/perl/make
  90. 79
      app/nginx-1.11.10/auto/lib/zlib/conf
  91. 135
      app/nginx-1.11.10/auto/lib/zlib/make
  92. 17
      app/nginx-1.11.10/auto/lib/zlib/makefile.bcc
  93. 17
      app/nginx-1.11.10/auto/lib/zlib/makefile.msvc
  94. 14
      app/nginx-1.11.10/auto/lib/zlib/makefile.owc
  95. 691
      app/nginx-1.11.10/auto/make
  96. 138
      app/nginx-1.11.10/auto/module
  97. 1372
      app/nginx-1.11.10/auto/modules
  98. 12
      app/nginx-1.11.10/auto/nohave
  99. 631
      app/nginx-1.11.10/auto/options
  100. 116
      app/nginx-1.11.10/auto/os/conf

7
.gitignore

@ -0,0 +1,7 @@
*~
*.a
*.core
*.lo
*.la
*.o
*.so

BIN
F-Stack.png

After

Width: 1294  |  Height: 566  |  Size: 48 KiB

216
LICENSE

@ -0,0 +1,216 @@
Main code of F-Stack is BSD 2-Clause licensed.
Copyright (C) 2017 THL A29 Limited, a Tencent company.
All rights reserved.
Other Dependencies:
------------------------------------------------------------------------------
This work contains some softwares from:
DPDK(http://dpdk.org/),
FreeBSD(https://www.freebsd.org/),
Nginx(http://nginx.org),
Redis(https://github.com/antirez/redis),
Microthread framework(https://github.com/Tencent/MSEC/tree/master/spp_rpc/src/sync_frame/micro_thread).
This work uses some codes from:
Libplebnet(https://gitorious.org/freebsd/kmm-sandbox/commit/fa8a11970bc0ed092692736f175925766bebf6af?p=freebsd:kmm-sandbox.git;a=tree;f=lib/libplebnet;h=ae446dba0b4f8593b69b339ea667e12d5b709cfb;hb=refs/heads/work/svn_trunk_libplebnet),
Libuinet(https://github.com/pkelsey/libuinet),
inih(https://github.com/benhoyt/inih).
1.DPDK
BSD 3-Clause, Copyright(c) 2010-2017 Intel Corporation.All rights reserved.
2.FreeBSD
BSD 2-Clause, Copyright 1992-2016 The FreeBSD Project. All rights reserved.
3.Libplebnet
BSD 2-Clause, Copyright (c) 2010-2011 Kip Macy.All rights reserved.
4.Libuinet
BSD 2-Clause, Copyright (c) 2015 Patrick Kelsey.All rights reserved.
5.inih(a simple .INI file parser)
BSD 3-Clause, Copyright (c) 2009, Ben Hoyt.All rights reserved.
6.Nginx
BSD 2-Clause, Copyright (C) 2002-2017 Igor Sysoev.
Copyright (C) 2011-2017 Nginx, Inc.All rights reserved.
7.Redis
BSD 2-Clause, Copyright (c) 2006-2015, Salvatore Sanfilippo.All rights reserved.
8.Microthread framework
GPL-2.0, Copyright (C) 2016 THL A29 Limited, a Tencent company.All rights reserved.
Terms of the BSD 2-Clause License:
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Terms of the BSD 3-Clause License:
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Terms of the GPL-2.0 License:
-------------------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
One line to give the program's name and a brief idea of what it does.
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
signature of Ty Coon, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.

106
README.md

@ -1,2 +1,106 @@
# F-Stack
Since the F-Stack project involves a large number of third party code, there are many open source licenses, copyrights need to be reviewed. So, the project is closed temporarily, and when this work is completed, we will reopen the project before April 24th.
![](F-Stack.png)
## Introduction
With the rapid development of NIC, the poor performance of data packets processing with Linux kernel has become the bottleneck. However, the rapid development of the Internet needs high performance of network processing, kernel bypass has caught more and more attention. There are various similar technologies appear, such as DPDK, NETMAP and PF_RING. The main idea of kernel bypass is that Linux is only used to deal with control flow, all data streams are processed in user space. Therefore, kernel bypass can avoid performance bottlenecks caused by kernel packet copy, thread scheduling, system calls and interrupt. Furthermore, kernel bypass can achieve higher performance with multi optimizing methods. Within various techniques, DPDK has been widely used because of its more thorough isolation from kernel scheduling and active community support.
[F-Stack](http://www.f-stack.org/?from=github) is an open source network framework with high performance based on DPDK. With follow characteristics
1. Ultra high network performance which can achieve network card under full load, 10 million concurrent connection, 5 million RPS, 1 million CPS.
2. Transplant FreeBSD 11.01 user space stack, provides a complete stack function, cut a great amount of irrelevant features. Therefore greatly enhance the performance.
3. Support Nginx, Redis and other mature applications, service can easily use F-Stack
4. With Multi-process architecture, easy to extend
5. Provide micro thread interface. Various applications with stateful app can easily use F-Stack to get high performance without processing complex asynchronous logic.
6. Provide Epoll/Kqueue interface that allow many kinds of applications easily use F-Stack
## History
In order to deal with the increasingly severe DDoS attacks, authorized DNS server of Tencent Cloud DNSPod switched from Gigabit Ethernet to 10-Gigabit at the end of 2012. We faced several options, one is to continue to use the original model another is to use kernel bypass technology. After several rounds of investigation, we finally chose to develop our next generation of DNS server based on DPDK. The reason is DPDK provides ultra-high performance and can be seamlessly extended to 40G, or even 100G NIC in the future.
After several months of development and testing, DKDNS, high-performance DNS server based on DPDK officially released in October 2013. It's capable of achieving up to 11 million QPS with a single 10GE port and 18.2 million QPS with two 10GE ports. And then we developed a user-space TCP/IP stack called F-Stack that can process 0.6 million RPS with a single 10GE port.
With the fast growth of Tencent Cloud, more and more services need higher network access performance. Meanwhile, F-Stack was continuous improving driven by the business growth, and ultimately developed into a general network access framework. But this TCP/IP stack couldn't meet the needs of these services while continue to develop and maintain a complete network stack will cost high, we've tried several plans and finally determined to port FreeBSD(11.0 stable) TCP/IP stack into F-Stack. Thus, we can reduce the cost of maintenance and follow up the improvement from community quickly.Thanks to [libplebnet](https://gitorious.org/freebsd/kmm-sandbox/commit/fa8a11970bc0ed092692736f175925766bebf6af?p=freebsd:kmm-sandbox.git;a=tree;f=lib/libplebnet;h=ae446dba0b4f8593b69b339ea667e12d5b709cfb;hb=refs/heads/work/svn_trunk_libplebnet) and [libuinet](https://github.com/pkelsey/libuinet), this work becomes a lot easier.
With the rapid development of all kinds of application, in order to help different APPs quick and easily use F-Stack, F-Stack has integrated Nginx, Redis and other commonly used APPs, and a micro thread framework, and provides a standard Epoll/Kqueue interface.
Currently, besides authorized DNS server of DNSPod, there are various products in Tencent Cloud has used the F-Stack, such as HttpDNS (D+), COS access module, CDN access module, etc..
## Quick Start
#clone F-Stack
mkdir /data/f-stack
git clone https://github.com/F-Stack/f-stack.git /data/f-stack
cd f-stack
# compile DPDK
cd dpdk/tools
./dpdk-setup.sh # compile with x86_64-native-linuxapp-gcc
# Set hugepage
# single-node system
echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
# or NUMA
echo 1024 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
echo 1024 > /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages
# Using Hugepage with the DPDK
mkdir /mnt/huge
mount -t hugetlbfs nodev /mnt/huge
# offload NIC
modprobe uio
insmod /data/f-stack/dpdk/x86_64-native-linuxapp-gcc/build/kmod/igb_uio.ko
insmod /data/f-stack/dpdk/x86_64-native-linuxapp-gcc/build/kmod/rte_kni.ko
python dpdk-devbind.py --status
ifconfig eth0 down
python dpdk-devbind.py --bind=igb_uio eth0 # assuming that use 10GE NIC and eth0
# Compile F-Stack
cd ../../lib/
make
export FF_PATH=/data/f-stack
export FF_DPDK=/data/f-stack/dpdk/x86_64-native-linuxapp-gcc/lib
#### Nginx
cd app/nginx-1.11.10
./configure --prefix=/usr/local/nginx_fstack --with-ff_module
make
make install
cd ../..
./start.sh -b /usr/local/nginx_fstack/sbin/nginx -c config.ini
#### Redis
cd app/redis-3.2.8/
make
make install
## Nginx Testing Result
Test environment
NIC:Intel Corporation Ethernet Controller XL710 for 40GbE QSFP+
CPU:Intel(R) Xeon(R) CPU E5-2670 v3 @ 2.30GHz
Memory:128G
OS:CentOS Linux release 7.2 (Final)
Kernel:3.10.104-1-tlinux2-0041.tl2
Nginx uses linux kernel's default config, all soft interrupts are working in the first CPU core.
Nginx si means modify the smp_affinity of every IRQ, so that the decision to service an interrupt with a particular CPU is made at the hardware level, with no intervention from the kernel.
CPS (Connection:close, Small data packet) test result
![](http://i.imgur.com/PvCRmXR.png)
RPS (Connection:Keep-Alive, Small data packet) test data
![](http://i.imgur.com/CTDPx3a.png)
Bandwidth (Connection:Keep-Alive, 3.7k bytes data packet) test data
![](http://i.imgur.com/1ZM6yT9.png)
## Licenses
See [LICENSE](LICENSE)

95
app/micro_thread/Makefile

@ -0,0 +1,95 @@
#
# Tencent is pleased to support the open source community by making MSEC available.
#
# Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
#
# Licensed under the GNU General Public License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You may
# obtain a copy of the License at
#
# https://opensource.org/licenses/GPL-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the
# License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
# either express or implied. See the License for the specific language governing permissions
# and limitations under the License.
#
########MAKEFILE##########
ifeq ($(FF_PATH),)
$(error variable FF_PATH is not set)
endif
DEBUG= -g
BINARY = libmt.a
FF_LIB=$(FF_PATH)/libfstack.a
DPDK_LIBS = $(shell pkg-config --define-variable=TOPDIR=${FF_PATH} --libs f-stack.pc)
# Comment the following line if you are not using the gnu c compiler
#C_ARGS = -Wall -g -fPIC -D_DEBUG
C_ARGS = -Wall -g -fPIC -O0 -DMT_REAL_TIME
#.SUFFIXES: .o .cpp
ifeq ($(ARCH),32)
C_ARGS += -march=pentium4 -m32 -DSUS_LINUX -pthread
else
C_ARGS += -m64 -DSUS_LINUX -pthread
endif
# You might have to change this if your c compiler is not cc
CC = g++
# You shouldn't need to make any more changes below this line.
INCCOMM=-I./valgrind -I$(FF_PATH)/lib
#.c.o:
# $(CC) -c $*.c
all: $(BINARY)
### shell color config
RED = \\e[1m\\e[31m
DARKRED = \\e[31m
GREEN = \\e[1m\\e[32m
DARKGREEN = \\e[32m
BLUE = \\e[1m\\e[34m
DARKBLUE = \\e[34m
YELLOW = \\e[1m\\e[33m
DARKYELLOW = \\e[33m
MAGENTA = \\e[1m\\e[35m
DARKMAGENTA = \\e[35m
CYAN = \\e[1m\\e[36m
DARKCYAN = \\e[36m
RESET = \\e[m
CRESET = ;echo -ne \\e[m; test -s $@
%.o: %.cpp
@echo -e Compiling $(GREEN)$<$(RESET) ...$(RED)
@$(CC) $(C_ARGS) -c -o $@ $< $(INCCOMM) $(CRESET)
%.o: %.c
@echo -e Compiling $(GREEN)$<$(RESET) ...$(RED)
@$(CC) $(C_ARGS) -c -o $@ $< $(INCCOMM) $(CRESET)
%.o: %.S
@echo -e Compiling $(GREEN)$<$(RESET) ...$(RED)
@$(CC) $(C_ARGS) -c -o $@ $< $(INCCOMM) $(CRESET)
clean:
@rm -f $(BINARY) *.a *.o echo
LIB_OBJ = micro_thread.o kqueue_proxy.o arch_ctx.o mt_session.o mt_notify.o mt_action.o mt_mbuf_pool.o mt_api.o\
mt_connection.o mt_concurrent.o mt_sys_hook.o ff_hook.o heap_timer.o mt_cache.o mt_net.o
libmt.a: $(LIB_OBJ)
@echo -e Linking $(CYAN)$@$(RESET) ...$(RED)
@-rm -f $@
@ar crs $@ $^ $(FST_LIB) $(CRESET)
@chmod +x $@
echo: echo.o libmt.a
@echo -e Compile $(CYAN)$@$(RESET) ...$(RED)
@$(CC) -O -gdwarf-2 -o $@ $^ -lstdc++ -ldl -lm $(DPDK_LIBS) $(CRESET)

157
app/micro_thread/arch_ctx.S

@ -0,0 +1,157 @@
/**
* Tencent is pleased to support the open source community by making MSEC available.
*
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the GNU General Public License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* https://opensource.org/licenses/GPL-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
#
# context x86 or x86_64 save and restore
#
# x86_64 x86
# 0 %rbx %ebx
# 1 %rsp %esp
# 2 %rbp %ebp
# 3 %r12 %esi
# 4 %r13 %edi
# 5 %r14 %eip
# 6 %r15
# 7 %rip
#if defined(__amd64__) || defined(__x86_64__)
##
# @brief save_context
##
.text
.align 4
.globl save_context
.type save_context, @function
save_context:
pop %rsi
xorl %eax,%eax
movq %rbx,(%rdi)
movq %rsp,8(%rdi)
push %rsi
movq %rbp,16(%rdi)
movq %r12,24(%rdi)
movq %r13,32(%rdi)
movq %r14,40(%rdi)
movq %r15,48(%rdi)
movq %rsi,56(%rdi)
ret
.size save_context,.-save_context
##
# @brief restore_context
##
.text
.align 4
.globl restore_context
.type restore_context, @function
restore_context:
movl %esi,%eax
movq (%rdi),%rbx
movq 8(%rdi),%rsp
movq 16(%rdi),%rbp
movq 24(%rdi),%r12
movq 32(%rdi),%r13
movq 40(%rdi),%r14
movq 48(%rdi),%r15
jmp *56(%rdi)
.size restore_context,.-restore_context
##
# @brief replace_esp
##
.text
.align 4
.globl replace_esp
.type replace_esp, @function
replace_esp:
movq %rsi,8(%rdi)
ret
.size replace_esp,.-replace_esp
#elif defined(__i386__)
##
# @brief save_context
##
.text
.align 4
.globl save_context
.type save_context, @function
save_context:
movl 4(%esp),%edx
popl %ecx
xorl %eax,%eax
movl %ebx,(%edx)
movl %esp,4(%edx)
pushl %ecx
movl %ebp,8(%edx)
movl %esi,12(%edx)
movl %edi,16(%edx)
movl %ecx,20(%edx)
ret
.size save_context,.-save_context
##
# @brief restore_context
##
.text
.align 4
.globl restore_context
.type restore_context, @function
restore_context:
movl 4(%esp),%edx
movl 8(%esp),%eax
movl (%edx),%ebx
movl 4(%edx),%esp
movl 8(%edx),%ebp
movl 12(%edx),%esi
movl 16(%edx),%edi
jmp *20(%edx)
.size restore_context,.-restore_context
##
# @brief replace_esp
##
.text
.align 4
.globl replace_esp
.type replace_esp, @function
replace_esp:
movl 4(%esp),%edx
movl 8(%esp),%eax
movl %eax,4(%edx)
ret
.size replace_esp,.-replace_esp
#else
#error "Linux cpu arch not supported"
#endif

102
app/micro_thread/echo.cpp

@ -0,0 +1,102 @@
#include <stdio.h>
#include <stdlib.h>
#include "mt_incl.h"
#include "micro_thread.h"
using namespace NS_MICRO_THREAD;
int set_fd_nonblock(int fd)
{
int nonblock = 1;
return ioctl(fd, FIONBIO, &nonblock);
}
int create_tcp_sock()
{
int fd;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
fprintf(stderr, "create tcp socket failed, error: %m\n");
return -1;
}
if (set_fd_nonblock(fd) == -1) {
fprintf(stderr, "set tcp socket nonblock failed\n");
return -1;
}
return fd;
}
void echo(void *arg)
{
int ret;
int *p = (int *)arg;
int clt_fd = *p;
delete p;
char buf[64 * 1024];
while (true) {
ret = mt_recv(clt_fd, (void *)buf, 64 * 1024, 0, -1);
if (ret < 0) {
printf("recv from client error\n");
break;
}
ret = mt_send(clt_fd, (void *)buf, ret, 0, 1000);
if (ret < 0) {
//printf("send data to client error\n");
break;
}
}
close(clt_fd);
}
int echo_server()
{
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(80);
int fd = create_tcp_sock();
if (fd < 0) {
fprintf(stderr, "create listen socket failed\n");
return -1;
}
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
close(fd);
fprintf(stderr, "bind failed [%m]\n");
return -1;
}
if (listen(fd, 1024) < 0) {
close(fd);
fprintf(stderr, "listen failed [%m]\n");
return -1;
}
int clt_fd = 0;
int *p;
while (true) {
struct sockaddr_in client_addr;
int addr_len = sizeof(client_addr);
clt_fd = mt_accept(fd, (struct sockaddr*)&client_addr, (socklen_t*)&addr_len, -1);
if (clt_fd < 0) {
mt_sleep(1);
continue;
}
if (set_fd_nonblock(clt_fd) == -1) {
fprintf(stderr, "set clt_fd nonblock failed [%m]\n");
break;
}
p = new int(clt_fd);
mt_start_thread((void *)echo, (void *)p);
}
return 0;
}
int main(int argc, char *argv[])
{
mt_init_frame("./config.ini", argc, argv);
echo_server();
}

561
app/micro_thread/epoll_proxy.cpp.bak

@ -0,0 +1,561 @@
/**
* Tencent is pleased to support the open source community by making MSEC available.
*
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the GNU General Public License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* https://opensource.org/licenses/GPL-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
/**
* @filename epoll_proxy.cpp
* @info epoll for micro thread manage
*/
#include "epoll_proxy.h"
#include "micro_thread.h"
using namespace NS_MICRO_THREAD;
/**
* @brief 构造函数
*/
EpollProxy::EpollProxy()
{
_maxfd = EpollProxy::DEFAULT_MAX_FD_NUM;
_epfd = -1;
_evtlist = NULL;
_eprefs = NULL;
}
/**
* @brief epoll初始化, 申请动态内存等
*/
int EpollProxy::InitEpoll(int max_num)
{
int rc = 0;
if (max_num > _maxfd) // 如果设置的数目较大, 则调整最大fd数目
{
_maxfd = max_num;
}
_epfd = epoll_create(_maxfd);
if (_epfd < 0)
{
rc = -1;
goto EXIT_LABEL;
}
fcntl(_epfd, F_SETFD, FD_CLOEXEC);
_eprefs = new FdRef[_maxfd];
if (NULL == _eprefs)
{
rc = -2;
goto EXIT_LABEL;
}
_evtlist = (EpEvent*)calloc(_maxfd, sizeof(EpEvent));
if (NULL == _evtlist)
{
rc = -3;
goto EXIT_LABEL;
}
struct rlimit rlim;
memset(&rlim, 0, sizeof(rlim));
if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
{
if ((int)rlim.rlim_max < _maxfd)
{
rlim.rlim_cur = rlim.rlim_max;
setrlimit(RLIMIT_NOFILE, &rlim);
rlim.rlim_cur = _maxfd;
rlim.rlim_max = _maxfd;
setrlimit(RLIMIT_NOFILE, &rlim);
}
}
EXIT_LABEL:
if (rc < 0)
{
TermEpoll();
}
return rc;
}
/**
* @brief epoll反初始化
*/
void EpollProxy::TermEpoll()
{
if (_epfd > 0)
{
close(_epfd);
_epfd = -1;
}
if (_evtlist != NULL)
{
free(_evtlist);
_evtlist = NULL;
}
if (_eprefs != NULL)
{
delete []_eprefs;
_eprefs = NULL;
}
}
/**
* @brief 将一个微线程侦听的所有socket送入epoll管理
* @param fdset 微线程侦听的socket集合
* @return true 成功, false 失败, 失败会尽力回滚, 减少影响
*/
bool EpollProxy::EpollAdd(EpObjList& obj_list)
{
bool ret = true;
EpollerObj *epobj = NULL;
EpollerObj *epobj_error = NULL;
TAILQ_FOREACH(epobj, &obj_list, _entry)
{
if (!EpollAddObj(epobj))
{
MTLOG_ERROR("epobj add failed, fd: %d", epobj->GetOsfd());
epoll_assert(0);
epobj_error = epobj;
ret = false;
goto EXIT_LABEL;
}
}
EXIT_LABEL:
if (!ret)
{
TAILQ_FOREACH(epobj, &obj_list, _entry)
{
if (epobj == epobj_error)
{
break;
}
EpollDelObj(epobj);
}
}
return ret;
}
/**
* @brief 将一个微线程侦听的所有socket移除epoll管理
* @param fdset 微线程侦听的socket集合
* @return true 成功, false 失败
*/
bool EpollProxy::EpollDel(EpObjList& obj_list)
{
bool ret = true;
EpollerObj *epobj = NULL;
TAILQ_FOREACH(epobj, &obj_list, _entry)
{
if (!EpollDelObj(epobj)) // failed also need continue, be sure ref count ok
{
MTLOG_ERROR("epobj del failed, fd: %d", epobj->GetOsfd());
epoll_assert(0);
ret = false;
}
}
return ret;
}
/**
* @brief 单个epfd更新epctrl, 成功需要更新当前监听事件值
*/
bool EpollProxy::EpollCtrlAdd(int fd, int events)
{
FdRef* item = FdRefGet(fd);
if (NULL == item)
{
MT_ATTR_API(320851, 1); // fd error
MTLOG_ERROR("epfd ref not find, failed, fd: %d", fd);
epoll_assert(0);
return false;
}
// 更新引用计数, 部分流程会依赖该计数, 失败要回滚
item->AttachEvents(events);
int old_events = item->GetListenEvents();
int new_events = old_events | events;
if (old_events == new_events) {
return true;
}
int op = old_events ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
EpEvent ev;
ev.events = new_events;
ev.data.fd = fd;
if ((epoll_ctl(_epfd, op, fd, &ev) < 0) && !(op == EPOLL_CTL_ADD && errno == EEXIST))
{
MT_ATTR_API(320850, 1); // epoll error
MTLOG_ERROR("epoll ctrl failed, fd: %d, op: %d, errno: %d", fd, op, errno);
item->DetachEvents(events);
epoll_assert(0);
return false;
}
item->SetListenEvents(new_events);
return true;
}
/**
* @brief 单个epfd更新epctrl, 成功需要更新当前监听事件值
*/
bool EpollProxy::EpollCtrlDel(int fd, int events)
{
return EpollCtrlDelRef(fd, events, false);
}
/**
* @brief 单个epfd更新epctrl, 检查引用计数, 可以预设长连接, 不会每次都epollctl
*/
bool EpollProxy::EpollCtrlDelRef(int fd, int events, bool use_ref)
{
FdRef* item = FdRefGet(fd);
if (NULL == item)
{
MT_ATTR_API(320851, 1); // fd error
MTLOG_ERROR("epfd ref not find, failed, fd: %d", fd);
epoll_assert(0);
return false;
}
item->DetachEvents(events); // delete 失败不回滚处理
int old_events = item->GetListenEvents();
int new_events = old_events &~ events; // 默认情况
// 如果要按引用删除, 需要核查是否满足删除条件
if (use_ref)
{
new_events = old_events;
if (0 == item->ReadRefCnt()) {
new_events = new_events & ~EPOLLIN;
}
if (0 == item->WriteRefCnt()) {
new_events = new_events & ~EPOLLOUT;
}
}
if (old_events == new_events)
{
return true;
}
int op = new_events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
EpEvent ev;
ev.events = new_events;
ev.data.fd = fd;
if ((epoll_ctl(_epfd, op, fd, &ev) < 0) && !(op == EPOLL_CTL_DEL && errno == ENOENT))
{
MT_ATTR_API(320850, 1); // epoll error
MTLOG_ERROR("epoll ctrl failed, fd: %d, op: %d, errno: %d", fd, op, errno);
epoll_assert(0);
return false;
}
item->SetListenEvents(new_events);
return true;
}
/**
* @brief 单个epfd更新epctrl, 如果失败, 完整回退
*/
bool EpollProxy::EpollAddObj(EpollerObj* obj)
{
if (NULL == obj)
{
MTLOG_ERROR("epobj input invalid, %p", obj);
return false;
}
FdRef* item = FdRefGet(obj->GetOsfd());
if (NULL == item)
{
MT_ATTR_API(320851, 1); // fd error
MTLOG_ERROR("epfd ref not find, failed, fd: %d", obj->GetOsfd());
epoll_assert(0);
return false;
}
// 不同的回调状态, 不同的方式处理 del 事件, 屏蔽连接复用方式的处理复杂性
int ret = obj->EpollCtlAdd(item);
if (ret < 0)
{
MTLOG_ERROR("epoll ctrl callback failed, fd: %d, obj: %p", obj->GetOsfd(), obj);
epoll_assert(0);
return false;
}
return true;
}
/**
* @brief 将一个微线程侦听的所有socket移除epoll管理
* @param fdset 微线程侦听的socket集合
* @return true 成功, false 失败
*/
bool EpollProxy::EpollDelObj(EpollerObj* obj)
{
if (NULL == obj)
{
MTLOG_ERROR("fdobj input invalid, %p", obj);
return false;
}
FdRef* item = FdRefGet(obj->GetOsfd());
if (NULL == item)
{
MT_ATTR_API(320851, 1); // fd error
MTLOG_ERROR("epfd ref not find, failed, fd: %d", obj->GetOsfd());
epoll_assert(0);
return false;
}
// 不同的回调状态, 不同的方式处理 del 事件, 屏蔽连接复用方式的处理复杂性
int ret = obj->EpollCtlDel(item);
if (ret < 0)
{
MTLOG_ERROR("epoll ctrl callback failed, fd: %d, obj: %p", obj->GetOsfd(), obj);
epoll_assert(0);
return false;
}
return true;
}
/**
* @brief 更新每个socket的最新接收事件信息
* @param evtfdnum 收到事件的fd集合数目
*/
void EpollProxy::EpollRcvEventList(int evtfdnum)
{
int ret = 0;
int osfd = 0;
int revents = 0;
FdRef* item = NULL;
EpollerObj* obj = NULL;
for (int i = 0; i < evtfdnum; i++)
{
osfd = _evtlist[i].data.fd;
item = FdRefGet(osfd);
if (NULL == item)
{
MT_ATTR_API(320851, 1); // fd error
MTLOG_ERROR("epfd ref not find, failed, fd: %d", osfd);
epoll_assert(0);
continue;
}
revents = _evtlist[i].events;
obj = item->GetNotifyObj();
if (NULL == obj)
{
MTLOG_ERROR("fd notify obj null, failed, fd: %d", osfd);
EpollCtrlDel(osfd, (revents & (EPOLLIN | EPOLLOUT)));
continue;
}
obj->SetRcvEvents(revents);
// 1. 错误处理, 完毕后直接跳出
if (revents & (EPOLLERR | EPOLLHUP))
{
obj->HangupNotify();
continue;
}
// 2. 可读事件, 非0返回值会跳出
if (revents & EPOLLIN) {
ret = obj->InputNotify();
if (ret != 0) {
continue;
}
}
// 3. 可写事件, 非0返回值会跳出
if (revents & EPOLLOUT) {
ret = obj->OutputNotify();
if (ret != 0) {
continue;
}
}
}
}
/**
* @brief epoll_wait 以及分发处理过程
*/
void EpollProxy::EpollDispath()
{
int wait_time = EpollGetTimeout();
int nfd = epoll_wait(_epfd, _evtlist, _maxfd, wait_time);
if (nfd <= 0) {
return;
}
EpollRcvEventList(nfd);
}
/**
* @brief 可读事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
*/
int EpollerObj::InputNotify()
{
MicroThread* thread = this->GetOwnerThread();
if (NULL == thread)
{
epoll_assert(0);
MTLOG_ERROR("Epoll fd obj, no thread ptr, wrong");
return -1;
}
// 多个事件同时到达, 防重复操作
if (thread->HasFlag(MicroThread::IO_LIST))
{
MtFrame* frame = MtFrame::Instance();
frame->RemoveIoWait(thread);
frame->InsertRunable(thread);
}
return 0;
}
/**
* @brief 可写事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
*/
int EpollerObj::OutputNotify()
{
MicroThread* thread = this->GetOwnerThread();
if (NULL == thread)
{
epoll_assert(0);
MTLOG_ERROR("Epoll fd obj, no thread ptr, wrong");
return -1;
}
// 多个事件同时到达, 防重复操作
if (thread->HasFlag(MicroThread::IO_LIST))
{
MtFrame* frame = MtFrame::Instance();
frame->RemoveIoWait(thread);
frame->InsertRunable(thread);
}
return 0;
}
/**
* @brief 异常通知接口, 关闭fd侦听, thread等待处理超时
* @return 忽略返回值, 跳过其它事件处理
*/
int EpollerObj::HangupNotify()
{
MtFrame* frame = MtFrame::Instance();
frame->EpollCtrlDel(this->GetOsfd(), this->GetEvents());
return 0;
}
/**
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
* @param args fd引用对象的指针
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
*/
int EpollerObj::EpollCtlAdd(void* args)
{
MtFrame* frame = MtFrame::Instance();
FdRef* fd_ref = (FdRef*)args;
epoll_assert(fd_ref != NULL);
int osfd = this->GetOsfd();
int new_events = this->GetEvents();
// 通知对象需要更新, FD通知对象理论上不会复用, 这里做冲突检查, 异常log记录
EpollerObj* old_obj = fd_ref->GetNotifyObj();
if ((old_obj != NULL) && (old_obj != this))
{
MTLOG_ERROR("epfd ref conflict, fd: %d, old: %p, now: %p", osfd, old_obj, this);
return -1;
}
fd_ref->SetNotifyObj(this);
// 调用框架的epoll ctl接口, 屏蔽epoll ctrl细节
if (!frame->EpollCtrlAdd(osfd, new_events))
{
MTLOG_ERROR("epfd ref add failed, log");
fd_ref->SetNotifyObj(old_obj);
return -2;
}
return 0;
}
/**
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
* @param args fd引用对象的指针
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
*/
int EpollerObj::EpollCtlDel(void* args)
{
MtFrame* frame = MtFrame::Instance();
FdRef* fd_ref = (FdRef*)args;
epoll_assert(fd_ref != NULL);
int osfd = this->GetOsfd();
int events = this->GetEvents();
// 通知对象需要更新, FD通知对象理论上不会复用, 这里做冲突检查, 异常log记录
EpollerObj* old_obj = fd_ref->GetNotifyObj();
if (old_obj != this)
{
MTLOG_ERROR("epfd ref conflict, fd: %d, old: %p, now: %p", osfd, old_obj, this);
return -1;
}
fd_ref->SetNotifyObj(NULL);
// 调用框架的epoll ctl接口, 屏蔽epoll ctrl细节
if (!frame->EpollCtrlDelRef(osfd, events, false)) // 引用有风险, 弊大于利, 关闭掉
{
MTLOG_ERROR("epfd ref del failed, log");
fd_ref->SetNotifyObj(old_obj);
return -2;
}
return 0;
}

434
app/micro_thread/epoll_proxy.h.bak

@ -0,0 +1,434 @@
/**
* Tencent is pleased to support the open source community by making MSEC available.
*
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the GNU General Public License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* https://opensource.org/licenses/GPL-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
/**
* @filename epoll_proxy.h
* @info epoll for micro thread manage
*/
#ifndef _EPOLL_PROXY___
#define _EPOLL_PROXY___
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/queue.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <sys/epoll.h>
#include <assert.h>
#include <set>
#include <vector>
using std::set;
using std::vector;
#define epoll_assert(statement)
//#define epoll_assert(statement) assert(statement)
namespace NS_MICRO_THREAD {
/******************************************************************************/
/* 操作系统头文件适配定义 */
/******************************************************************************/
/**
* @brief add more detail for linux <sys/queue.h>, freebsd and University of California
* @info queue.h version 8.3 (suse) diff version 8.5 (tlinux)
*/
#ifndef TAILQ_CONCAT
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
#define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST((head)); \
(var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_CONCAT(head1, head2, field) \
do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
} \
} while (0)
#endif
#ifndef TAILQ_FOREACH_SAFE // tlinux no this define
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#endif
/******************************************************************************/
/* Epoll proxy 定义与实现部分 */
/******************************************************************************/
class EpollProxy;
class MicroThread;
/**
* @brief epoll通知对象基类定义
*/
class EpollerObj
{
protected:
int _fd; ///< 系统FD 或 socket
int _events; ///< 监听的事件类型
int _revents; ///< 收到的事件类型
int _type; ///< 工厂类别定义
MicroThread* _thread; ///< 关联线程指针对象
public:
TAILQ_ENTRY(EpollerObj) _entry; ///< 关联微线程的管理入口
/**
* @brief 构造与析构函数
*/
explicit EpollerObj(int fd = -1) {
_fd = fd;
_events = 0;
_revents = 0;
_type = 0;
_thread = NULL;
};
virtual ~EpollerObj(){};
/**
* @brief 可读事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
*/
virtual int InputNotify();
/**
* @brief 可写事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
*/
virtual int OutputNotify();
/**
* @brief 异常通知接口
* @return 忽略返回值, 跳过其它事件处理
*/
virtual int HangupNotify();
/**
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
* @param args fd引用对象的指针
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
*/
virtual int EpollCtlAdd(void* args);
/**
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
* @param args fd引用对象的指针
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
*/
virtual int EpollCtlDel(void* args);
/**
* @brief fd打开可读事件侦听
*/
void EnableInput() { _events |= EPOLLIN; };
/**
* @brief fd打开可写事件侦听
*/
void EnableOutput() { _events |= EPOLLOUT; };
/**
* @brief fd关闭可读事件侦听
*/
void DisableInput() { _events &= ~EPOLLIN; };
/**
* @brief fd关闭可写事件侦听
*/
void DisableOutput() { _events &= ~EPOLLOUT; };
/**
* @brief 系统socket设置读取封装
*/
int GetOsfd() { return _fd; };
void SetOsfd(int fd) { _fd = fd; };
/**
* @brief 监听事件与收到事件的访问方法
*/
int GetEvents() { return _events; };
void SetRcvEvents(int revents) { _revents = revents; };
int GetRcvEvents() { return _revents; };
/**
* @brief 工厂管理方法, 获取真实类型
*/
int GetNtfyType() { return _type; };
virtual void Reset() {
_fd = -1;
_events = 0;
_revents = 0;
_type = 0;
_thread = NULL;
};
/**
* @brief 设置与获取所属的微线程句柄接口
* @param thread 关联的线程指针
*/
void SetOwnerThread(MicroThread* thread) { _thread = thread; };
MicroThread* GetOwnerThread() { return _thread; };
};
typedef TAILQ_HEAD(__EpFdList, EpollerObj) EpObjList; ///< 高效的双链管理
typedef struct epoll_event EpEvent; ///< 重定义一下epoll event
/**
* @brief EPOLL支持同一FD多个线程侦听, 建立一个引用计数数组, 元素定义
* @info 引用计数弊大于利, 没有实际意义, 字段保留, 功能移除掉 20150623
*/
class FdRef
{
private:
int _wr_ref; ///< 监听写的引用计数
int _rd_ref; ///< 监听读的引用计数
int _events; ///< 当前正在侦听的事件列表
int _revents; ///< 当前该fd收到的事件信息, 仅在epoll_wait后处理中有效
EpollerObj* _epobj; ///< 单独注册调度器对象,一个fd关联一个对象
public:
/**
* @brief 构造与析构函数
*/
FdRef() {
_wr_ref = 0;
_rd_ref = 0;
_events = 0;
_revents = 0;
_epobj = NULL;
};
~FdRef(){};
/**
* @brief 监听事件获取与设置接口
*/
void SetListenEvents(int events) {
_events = events;
};
int GetListenEvents() {
return _events;
};
/**
* @brief 监听对象获取与设置接口
*/
void SetNotifyObj(EpollerObj* ntfy) {
_epobj = ntfy;
};
EpollerObj* GetNotifyObj() {
return _epobj;
};
/**
* @brief 监听引用计数的更新
*/
void AttachEvents(int event) {
if (event & EPOLLIN) {
_rd_ref++;
}
if (event & EPOLLOUT){
_wr_ref++;
}
};
void DetachEvents(int event) {
if (event & EPOLLIN) {
if (_rd_ref > 0) {
_rd_ref--;
} else {
_rd_ref = 0;
}
}
if (event & EPOLLOUT){
if (_wr_ref > 0) {
_wr_ref--;
} else {
_wr_ref = 0;
}
}
};
/**
* @brief 获取引用计数
*/
int ReadRefCnt() { return _rd_ref; };
int WriteRefCnt() { return _wr_ref; };
};
/**
* @brief EPOLL代理, 封装epoll操作与epoll全局数据
*/
class EpollProxy
{
public:
static const int DEFAULT_MAX_FD_NUM = 100000; ///< 默认最大监控的fd
private:
int _epfd; ///< epoll 主句柄
int _maxfd; ///< 最大的文件句柄数
EpEvent* _evtlist; ///< epoll返回给用户的事件列表指针
FdRef* _eprefs; ///< 用户监听的事件本地管理数组
public:
/**
* @brief 构造与析构函数
*/
EpollProxy();
virtual ~EpollProxy(){};
/**
* @brief epoll初始化与终止处理, 申请动态内存等
* @param max_num 最大可管理的fd数目
*/
int InitEpoll(int max_num);
void TermEpoll(void);
/**
* @brief epoll_wait 获取最大等待时间接口
* @return 目前需要等待的时间, 单位MS
*/
virtual int EpollGetTimeout(void) { return 0;};
/**
* @brief epoll 触发调度接口
* @param fdlist 多路并发请求, 所有发送的socket集合
* @param fd 单个socket, 触发等待
* @param timeout 超时时间设置, 毫秒
* @return true 成功, false 失败
*/
virtual bool EpollSchedule(EpObjList* fdlist, EpollerObj* fd, int timeout) { return false;};
/**
* @brief 将一个微线程侦听的所有socket送入epoll管理
* @param fdset 微线程侦听的socket集合
* @return true 成功, false 失败
*/
bool EpollAdd(EpObjList& fdset);
/**
* @brief 将一个微线程侦听的所有socket移除epoll管理
* @param fdset 微线程侦听的socket集合
* @return true 成功, false 失败
*/
bool EpollDel(EpObjList& fdset);
/**
* @brief epoll_wait 以及分发处理过程
*/
void EpollDispath(void);
/**
* @brief 单独一个fd注册, 关联侦听事件
* @param fd 文件句柄与事件信息
* @param obj epoll回调对象
*/
bool EpollAddObj(EpollerObj* obj);
/**
* @brief 取消一个fd注册, 关联侦听事件
* @param fd 文件句柄与事件信息
* @param obj epoll回调对象
*/
bool EpollDelObj(EpollerObj* obj);
/**
* @brief 封装epoll ctl的处理与当前监听事件的记录, 内部接口
* @param fd 操作的文件句柄
* @param new_events 需要新增的监听事件
*/
bool EpollCtrlAdd(int fd, int new_events);
/**
* @brief 封装epoll ctl的处理与当前监听事件的记录, 内部接口
* @param fd 操作的文件句柄
* @param new_events 需要新删除的监听事件
*/
bool EpollCtrlDel(int fd, int new_events);
bool EpollCtrlDelRef(int fd, int new_events, bool use_ref);
/**
* @brief 根据fd获取本地引用的结构, 按fd生成策略, 目前简单管理
* @param fd 文件描述符
* @return 本地文件引用结构, NULL 表示失败
*/
FdRef* FdRefGet(int fd) {
return ((fd >= _maxfd) || (fd < 0)) ? (FdRef*)NULL : &_eprefs[fd];
};
/**
* @brief 单独的注册接口, 用于注册或取消注册通知对象
* @param fd 操作的文件句柄
* @param obj 待注册或取消注册的对象
*/
void EpollNtfyReg(int fd, EpollerObj* obj) {
FdRef* ref = FdRefGet(fd);
if (ref) {
ref->SetNotifyObj(obj);
}
};
protected:
/**
* @brief 更新每个socket的最新接收事件信息
* @param evtfdnum 收到事件的fd集合数目
*/
void EpollRcvEventList(int evtfdnum);
};
}//NAMESPCE
#endif

7
app/micro_thread/f-stack.pc

@ -0,0 +1,7 @@
DPDK = ${TOPDIR}/dpdk/x86_64-native-linuxapp-gcc
Name: F-Stack
Description: F-Stack pkg-config pc
Version: 1.0
Libs: -L${TOPDIR}/lib -Wl,--whole-archive,-lfstack,--no-whole-archive -Wl,--no-as-needed -fvisibility=default -pthread -lm -lrt -L${DPDK}/lib -Wl,--whole-archive -lrte_pmd_vmxnet3_uio -lrte_pmd_i40e -lrte_pmd_ixgbe -lrte_pmd_e1000 -lrte_pmd_ring -Wl,--whole-archive -lrte_hash -lrte_kvargs -Wl,-lrte_mbuf -lethdev -lrte_eal -Wl,-lrte_mempool -lrte_ring -lrte_cmdline -lrte_cfgfile -lrte_kni -lrte_timer -Wl,-lrte_pmd_virtio -Wl,--no-whole-archive -lrt -lm -ldl -lcrypto
Cflags: -Wall -Werror -include ${DPDK}/include/rte_config.h -I${DPDK}/include -march=native -DRTE_MACHINE_CPUFLAG_SSE -DRTE_MACHINE_CPUFLAG_SSE2 -DRTE_MACHINE_CPUFLAG_SSE3 -DRTE_MACHINE_CPUFLAG_SSSE3 -DRTE_MACHINE_CPUFLAG_SSE4_1 -DRTE_MACHINE_CPUFLAG_SSE4_2 -DRTE_COMPILE_TIME_CPUFLAGS=RTE_CPUFLAG_SSE,RTE_CPUFLAG_SSE2,RTE_CPUFLAG_SSE3,RTE_CPUFLAG_SSSE3,RTE_CPUFLAG_SSE4_1,RTE_CPUFLAG_SSE4_2

222
app/micro_thread/ff_hook.cpp

@ -0,0 +1,222 @@
/**
* Tencent is pleased to support the open source community by making MSEC available.
*
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the GNU General Public License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* https://opensource.org/licenses/GPL-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sched.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdarg.h>
#include "ff_api.h"
#include "mt_sys_hook.h"
#include "ff_hook.h"
/*
void ff_hook_new_fd(int fd)
{
if (fd < 0 || fd >= ff_HOOK_MAX_FD) {
return;
}
g_ff_hook_fd_tab[fd] = 1;
}
bool ff_hook_find_fd(int fd) {
if (fd < 0 || fd >= ff_HOOK_MAX_FD) {
return false;
}
if (g_ff_hook_fd_tab[fd] == 1) {
return true;
} else {
return false;
}
}
void ff_hook_free_fd(int fd)
{
if (fd < 0 || fd >= ff_HOOK_MAX_FD) {
return;
}
g_ff_hook_fd_tab[fd] = 0;
}
*/
int ff_hook_socket(int domain, int type, int protocol)
{
if (!ff_hook_active() || (AF_INET != domain) || (SOCK_STREAM != type && SOCK_DGRAM != type)) {
return mt_real_func(socket)(domain, type, protocol);
}
int fd