pax_global_header00006660000000000000000000000064121074402620014510gustar00rootroot0000000000000052 comment=ad647015965b64595eb9a7b0c53b5c4a8f6bbefb ivykis-0.36.2/000077500000000000000000000000001210744026200131165ustar00rootroot00000000000000ivykis-0.36.2/.gitignore000066400000000000000000000006221210744026200151060ustar00rootroot00000000000000# aclocal aclocal.m4 autom4te.cache # autoconf configure config.guess config.sub # automake Makefile.in .deps/ # automake --missing compile depcomp install-sh missing # autoheader config.h.in # libtool libtool ltmain.sh .libs/ # editor backup files *~ # Generated files config.h config.status config.log misc/ivykis.pc src/include/iv.h stamp-h1 Makefile # Compiled files *.o *.lo *.la *.a *.so ivykis-0.36.2/AUTHORS000066400000000000000000000000521210744026200141630ustar00rootroot00000000000000Lennert Buytenhek ivykis-0.36.2/COPYING000066400000000000000000000636421210744026200141640ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. 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. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ivykis-0.36.2/DEDICATION000066400000000000000000000000361210744026200144430ustar00rootroot00000000000000Dedicated to Marija Kulikova. ivykis-0.36.2/Makefile.am000066400000000000000000000002521210744026200151510ustar00rootroot00000000000000SUBDIRS = src test if HAVE_POSIX SUBDIRS += contrib misc if !BUILD_ON_CYGWIN SUBDIRS += man3 endif endif EXTRA_DIST = DEDICATION libivykis.posix.ver libivykis.win32.ver ivykis-0.36.2/configure.ac000066400000000000000000000267121210744026200154140ustar00rootroot00000000000000AC_PREREQ(2.59) AC_INIT([ivykis], [0.36.2], [libivykis-discuss@lists.sourceforge.net]) AC_CONFIG_SRCDIR([src/iv_avl.c]) AC_CONFIG_HEADER(config.h) AM_INIT_AUTOMAKE([foreign]) # # On AIX 7.1, prevent AC_PROG_CC from adding -g to CFLAGS, as that # leads to the following linker error: "The symbol refers to a csect # with symbol number 0, which was not found. The new symbol cannot # be associated with a csect and is being ignored." # AC_CANONICAL_HOST case $host_os in aix7.*) ac_cv_prog_cc_g=no ;; *) ;; esac # Checks for programs. LT_INIT AC_PROG_CC AC_PROG_LIBTOOL # Build with -Wall. CFLAGS="$CFLAGS -Wall" # Check the host operating system type: posix or win32. AC_MSG_CHECKING([host operating system type]) AC_COMPILE_IFELSE([AC_LANG_SOURCE( #include #ifndef _POSIX_VERSION #error not POSIX #endif )], [ac_cv_host_system=posix AC_MSG_RESULT([posix])], [AC_COMPILE_IFELSE([AC_LANG_SOURCE( #ifndef _WIN32 #error not WIN32 #endif )], [ac_cv_host_system=win32 AC_MSG_RESULT([win32])], [AC_MSG_RESULT([unknown]) AC_MSG_ERROR(Can't determine host system type.)])]) if test $ac_cv_host_system = posix then # Check for __thread. AC_MSG_CHECKING([for working __thread]) case $host_os-$host_cpu in aix*) # # On at least AIX 5.1 and 7.1, __thread seems to be silently # ignored, and different threads get the same storage location # for __thread variables. # AC_MSG_RESULT([no]) ;; netbsd*) # # Unspecified brokenness on NetBSD 5.1. # AC_MSG_RESULT([no]) ;; solaris*-sparc) # # On at least Solaris 10 for SPARC, use of __thread produces # the following linker error: "ld: fatal: relocation error: # R_SPARC_TLS_DTPOFF32: file lib/.libs/libivykis.a(iv_main.o): # symbol __st: offset 0xfeee01e5 is non-aligned". # AC_MSG_RESULT([no]) ;; *) _AC_COMPILE_IFELSE([AC_LANG_SOURCE(static __thread int p = 0;)], [AC_DEFINE(HAVE_THREAD, 1, Define to 1 if compiler supports __thread.) AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) ;; esac # OS-specific preprocessor defines. case $host_os in hpux*) # # On HP-UX, we need -D_XOPEN_SOURCE=500 so that the # Berkeley socket API uses 'socklen_t' instead of int. # CFLAGS="$CFLAGS -D_XOPEN_SOURCE=500" ;; osf*) # # On Tru64, we need -D_BSD to get a definition for 'union # wait', and -D_POSIX_PII_SOCKET so that sys/socket.h defines # 'socklen_t'. # CFLAGS="$CFLAGS -D_BSD -D_POSIX_PII_SOCKET" ;; esac # # Check for pthreads support. # # At least Tru64 needs -pthread, to avoid the following error when # including pthread.h: # # pthread.h:339:4: error: #error "Please compile the module # including pthread.h with -pthread" # ac_save_CFLAGS=$CFLAGS ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes AC_CACHE_CHECK(whether $CC accepts -pthread, ac_cv_prog_cc_pthread, [ac_cv_prog_cc_pthread=no CFLAGS="-pthread" _AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [ac_cv_prog_cc_pthread=yes], []) ]) if test $ac_cv_prog_cc_pthread = yes then CFLAGS="$ac_save_CFLAGS -pthread" else CFLAGS=$ac_save_CFLAGS fi ac_c_werror_flag=$ac_save_c_werror_flag # # At least Solaris 11 for x86 needs building with -pthreads to # avoid run-time breakage in multithreaded applications. # ac_save_CFLAGS=$CFLAGS ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes AC_CACHE_CHECK(whether $CC accepts -pthreads, ac_cv_prog_cc_pthreads, [ac_cv_prog_cc_pthreads=no CFLAGS="-pthreads" _AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [ac_cv_prog_cc_pthreads=yes], []) ]) if test $ac_cv_prog_cc_pthreads = yes then CFLAGS="$ac_save_CFLAGS -pthreads" else CFLAGS=$ac_save_CFLAGS fi ac_c_werror_flag=$ac_save_c_werror_flag # # On Linux, linking against libpthread.so.0 doesn't give you # pthread_atfork(), as the latter is defined in libpthread_nonshared.a, # which doesn't get pulled in if libpthread.so.0 is pulled in # indirectly, e.g. via -lrt, but does get pulled in if you link against # -lpthread, as libpthread.so is a linker script that references both # libpthread.so.0 and libpthread_nonshared.a. Therefore, we test for # pthread_atfork(), to make sure that libpthread.so really does get # pulled in explicitly via -lpthread rather than implicitly via another # shared library dependency. # # However, on FreeBSD, pthread_atfork() is provided by libc.so, and # so, testing for pthread_atfork() in AC_SEARCH_LIBS() doesn't end up # making the other pthreads functions available in the linking stage. # Additionally test for pthread_create() to handle this. # # On SCO OpenServer Release 6 and SCO UnixWare 7.1.4, the pthread # functions appear to live in libthread, so check for that in # addition to checking for libpthread. # # Tru64 uses mangled symbol names in its libpthread, and has some # preprocessor magic in its pthread.h to do the same mangling, and # so, testing for pthreads symbols without including pthread.h # doesn't work. Since AC_SEARCH_LIBS() doesn't allow specifying a # header file to be included for tests (and on Tru64, we can't # include pthread.h without additionally specifying -pthread), we'll # check for __pthread_create if pthread_create does not exist. # # On HP-UX, libpthread uses mangled symbol names like on Tru64, but # what's worse, the HP-UX C library provides stub versions of almost # all libpthread functions that return errors instead of doing what # they are supposed to, and there's no way to detect this at compile # time. However, there are a number of symbols in libpthread that # the C library doesn't define stubs for, and we can test for one of # those (pthread_trace_notify_np is one of those symbols). # AC_SEARCH_LIBS([pthread_atfork], [pthread thread], [], AC_MSG_ERROR(pthreads support is required to build ivykis.)) AC_SEARCH_LIBS([pthread_create], [pthread], [], AC_SEARCH_LIBS([__pthread_create], [pthread], [], AC_SEARCH_LIBS([pthread_trace_notify_np], [pthread], [], AC_MSG_ERROR(pthreads support is required to build ivykis.)))) # # Check for __sync_lock_test_and_set(). We can't use AC_CHECK_FUNCS # for this, as autoconf will spit out a dummy definition for the # function we are testing for, and call it without any arguments, # which will prevent gcc from using the intrinsic. # AC_CACHE_CHECK(for __sync_lock_test_and_set(), ac_cv_func_sync_lock_test_and_set, [ac_cv_func_sync_lock_test_and_set=no _AC_LINK_IFELSE([AC_LANG_SOURCE( int main() { unsigned long test; while (__sync_lock_test_and_set(&test, 1) == 1) ; return 0; } )], [ac_cv_func_sync_lock_test_and_set=yes], []) ]) if test $ac_cv_func_sync_lock_test_and_set = yes then AC_DEFINE(HAVE_SYNC_LOCK_TEST_AND_SET, 1, Define to 1 if system has __sync_lock_test_and_set) fi # Checks for header files. AC_CHECK_HEADERS([process.h]) AC_CHECK_HEADERS([sys/devpoll.h]) AC_CHECK_HEADERS([sys/eventfd.h]) AC_CHECK_HEADERS([sys/syscall.h]) # Older FreeBSDs (6.1) don't include sys/ucontext.h in sys/thr.h. AC_CHECK_HEADERS([sys/thr.h], [], [], [#include ]) AC_CHECK_HEADERS([thread.h]) # Check for header file. AC_CACHE_CHECK(for linux/netfilter_ipv4.h, ac_cv_header_linux_netfilter_ipv4_h, [ac_cv_header_linux_netfilter_ipv4_h=no _AC_COMPILE_IFELSE([AC_LANG_SOURCE( #include #include )], [ac_cv_header_linux_netfilter_ipv4_h=yes], []) ]) # Check which header file defines 'struct timespec'. for hdr in sys/time.h sys/timers.h time.h pthread.h do AC_CHECK_MEMBER(struct timespec.tv_sec, [ac_cv_timespec_hdr=$hdr; break], [unset ac_cv_member_struct_timespec_tv_sec], [#include <$hdr>]) done if test x$ac_cv_timespec_hdr = x then AC_MSG_ERROR(Can't find definition of struct timespec.) fi AC_SUBST(ac_cv_timespec_hdr) # # Check for clock_gettime() and available time sources. (We cannot # test for the CLOCK_* constants by using #ifdef, as they are enums # and not defines on at least HP-UX 11.) # AC_SEARCH_LIBS([clock_gettime], [rt]) AC_CHECK_FUNCS([clock_gettime]) if test $ac_cv_func_clock_gettime = yes then AC_CACHE_CHECK(for CLOCK_MONOTONIC, ac_cv_define_clock_monotonic, [ac_cv_define_clock_monotonic=no _AC_COMPILE_IFELSE([AC_LANG_SOURCE( #include #include int p = CLOCK_MONOTONIC; )], [ac_cv_define_clock_monotonic=yes], []) ]) if test $ac_cv_define_clock_monotonic = yes then AC_DEFINE(HAVE_CLOCK_MONOTONIC, 1, Define to 1 if system has CLOCK_MONOTONIC) fi AC_CACHE_CHECK(for CLOCK_REALTIME, ac_cv_define_clock_realtime, [ac_cv_define_clock_realtime=no _AC_COMPILE_IFELSE([AC_LANG_SOURCE( #include #include int p = CLOCK_REALTIME; )], [ac_cv_define_clock_realtime=yes], []) ]) if test $ac_cv_define_clock_realtime = yes then AC_DEFINE(HAVE_CLOCK_REALTIME, 1, Define to 1 if system has CLOCK_REALTIME) fi fi # Checks for libraries. AC_SEARCH_LIBS([inet_ntop], [nsl]) AC_SEARCH_LIBS([socket], [socket]) AC_SEARCH_LIBS([thr_self], [thread]) # Checks for library functions. AC_CHECK_FUNCS([epoll_create]) AC_CHECK_FUNCS([epoll_create1]) AC_CHECK_FUNCS([eventfd]) AC_CHECK_FUNCS([gettid]) AC_CHECK_FUNCS([inotify_init]) AC_CHECK_FUNCS([kqueue]) AC_CHECK_FUNCS([lwp_gettid]) AC_CHECK_FUNCS([port_create]) AC_CHECK_FUNCS([pthread_spin_lock]) AC_CHECK_FUNCS([thr_self]) # # Only test for splice(2) on Linux, to avoid confusing it with a # system function on AIX 5.1 with the same name. # case $host_os in linux*) AC_CHECK_FUNCS([splice]) ;; *) ;; esac # Check whether wait4(2) is usable. case $host_os in aix*) # # AIX 5.1 and 7.1 have a broken wait4(2) implementation # that sometimes drops events on the floor, so use waitpid(2) # instead. # ;; nto-qnx*) # # Calls to wait4(2) with pid == -1 don't return any events on # QNX at all for some reason (and there are no man pages on # the QNX machine I have access to, so I can't find out why). # waitpid(2) seems to work, though. # ;; solaris*) # # The Solaris version of wait4(2) interprets a pid argument # of -1 as an instruction to wait for processes in process # group ID 1 (instead of waiting for all processes), which # is not what we want, so use waitpid(2) instead. # ;; *) AC_CHECK_FUNCS([wait4]) ;; esac # Check for linker version script support. ac_save_LDFLAGS=$LDFLAGS AC_CACHE_CHECK(whether $LD supports symbol version scripts, ac_cv_prog_ld_version_script, [ac_cv_prog_ld_version_script=no echo "TEST { local: *; };" > conftest.ver LDFLAGS="$LDFLAGS -Wl,--version-script,conftest.ver" _AC_LINK_IFELSE([AC_LANG_PROGRAM()], [ac_cv_prog_ld_version_script=yes], []) ]) LDFLAGS=$ac_save_LDFLAGS else # Build a libivykis DLL. AC_LIBTOOL_WIN32_DLL fi # Conditionals for OS type. AM_CONDITIONAL([HAVE_POSIX], [test $ac_cv_host_system = posix]) AM_CONDITIONAL([HAVE_WIN32], [test $ac_cv_host_system = win32]) # Conditionals for poll methods. AM_CONDITIONAL([HAVE_DEV_POLL], [test x$ac_cv_header_sys_devpoll_h = xyes]) AM_CONDITIONAL([HAVE_EPOLL], [test x$ac_cv_func_epoll_create = xyes]) AM_CONDITIONAL([HAVE_KQUEUE], [test x$ac_cv_func_kqueue = xyes]) AM_CONDITIONAL([HAVE_PORT], [test x$ac_cv_func_port_create = xyes]) # Other conditionals. AM_CONDITIONAL([BUILD_ON_CYGWIN], [test $build_os = cygwin]) AM_CONDITIONAL([HAVE_INOTIFY], [test x$ac_cv_func_inotify_init = xyes]) AM_CONDITIONAL([HAVE_LINUX_NETFILTER_IPV4_H], [test x$ac_cv_header_linux_netfilter_ipv4_h = xyes]) AM_CONDITIONAL([HAVE_VERSIONING], [test x$ac_cv_prog_ld_version_script = xyes]) AC_CONFIG_FILES([Makefile \ contrib/Makefile \ contrib/iv_getaddrinfo/Makefile \ contrib/kojines/Makefile \ man3/Makefile \ misc/Makefile \ misc/ivykis.pc \ src/Makefile \ src/include/iv.h \ test/Makefile]) AC_OUTPUT ivykis-0.36.2/contrib/000077500000000000000000000000001210744026200145565ustar00rootroot00000000000000ivykis-0.36.2/contrib/00README.txt000066400000000000000000000006271210744026200164210ustar00rootroot00000000000000 This directory holds ivykis example programs and contributed ivykis modules. iv_getaddrinfo/ A nonblocking DNS stub resolver module. kojines/ Application that accepts connections forwarded to it by the iptables REDIRECT target, and forwards them to a remote SOCKS5 proxy, using the original destination address of the REDIRECTed connection as the destination address in the SOCKS5 proxy request. ivykis-0.36.2/contrib/Makefile.am000066400000000000000000000001551210744026200166130ustar00rootroot00000000000000SUBDIRS = iv_getaddrinfo if HAVE_LINUX_NETFILTER_IPV4_H SUBDIRS += kojines endif EXTRA_DIST = 00README.txt ivykis-0.36.2/contrib/iv_getaddrinfo/000077500000000000000000000000001210744026200175425ustar00rootroot00000000000000ivykis-0.36.2/contrib/iv_getaddrinfo/Makefile.am000066400000000000000000000003511210744026200215750ustar00rootroot00000000000000AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/src/include -I$(top_builddir)/src/include LDADD = $(top_builddir)/src/libivykis.la noinst_PROGRAMS = test test_SOURCES = test.c iv_getaddrinfo.c noinst_HEADERS = iv_getaddrinfo.h ivykis-0.36.2/contrib/iv_getaddrinfo/iv_getaddrinfo.c000066400000000000000000000072631210744026200227020ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2011 Lennert Buytenhek * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include "iv_getaddrinfo.h" struct iv_getaddrinfo_thr_info { int num_requests; struct iv_work_pool pool; }; static void iv_getaddrinfo_tls_init_thread(void *_tinfo) { struct iv_getaddrinfo_thr_info *tinfo = _tinfo; tinfo->num_requests = 0; IV_WORK_POOL_INIT(&tinfo->pool); tinfo->pool.max_threads = 100; tinfo->pool.cookie = NULL; tinfo->pool.thread_start = NULL; tinfo->pool.thread_stop = NULL; } static struct iv_tls_user iv_getaddrinfo_tls_user = { .sizeof_state = sizeof(struct iv_getaddrinfo_thr_info), .init_thread = iv_getaddrinfo_tls_init_thread, }; static void iv_getaddrinfo_tls_init(void) __attribute__((constructor)); static void iv_getaddrinfo_tls_init(void) { iv_tls_user_register(&iv_getaddrinfo_tls_user); } struct iv_getaddrinfo_task { struct iv_getaddrinfo *ig; struct iv_work_item work; char *node; char *service; int have_hints; struct addrinfo hints; int ret; struct addrinfo *res; }; static void iv_getaddrinfo_task_work(void *_igt) { struct iv_getaddrinfo_task *igt = _igt; igt->ret = getaddrinfo(igt->node, igt->service, igt->have_hints ? &igt->hints : NULL, &igt->res); } static void iv_getaddrinfo_task_complete(void *_igt) { struct iv_getaddrinfo_task *igt = _igt; struct iv_getaddrinfo *ig; struct iv_getaddrinfo_thr_info *tinfo; ig = igt->ig; if (ig != NULL) ig->handler(ig->cookie, igt->ret, igt->res); else freeaddrinfo(igt->res); free(igt->node); free(igt->service); free(igt); tinfo = iv_tls_user_ptr(&iv_getaddrinfo_tls_user); if (!--tinfo->num_requests) iv_work_pool_put(&tinfo->pool); } int iv_getaddrinfo_submit(struct iv_getaddrinfo *ig) { struct iv_getaddrinfo_task *igt; struct iv_getaddrinfo_thr_info *tinfo; igt = calloc(1, sizeof(*igt)); if (igt == NULL) return -1; igt->ig = ig; IV_WORK_ITEM_INIT(&igt->work); igt->work.cookie = igt; igt->work.work = iv_getaddrinfo_task_work; igt->work.completion = iv_getaddrinfo_task_complete; if (ig->node != NULL) { igt->node = strdup(ig->node); if (igt->node == NULL) { free(igt); return -1; } } if (ig->service != NULL) { igt->service = strdup(ig->service); if (igt->service == NULL) { free(igt->node); free(igt); return -1; } } if (ig->hints != NULL) { igt->hints.ai_family = ig->hints->ai_family; igt->hints.ai_socktype = ig->hints->ai_socktype; igt->hints.ai_protocol = ig->hints->ai_protocol; igt->hints.ai_flags = ig->hints->ai_flags; igt->have_hints = 1; } tinfo = iv_tls_user_ptr(&iv_getaddrinfo_tls_user); if (!tinfo->num_requests++) iv_work_pool_create(&tinfo->pool); iv_work_pool_submit_work(&tinfo->pool, &igt->work); return 0; } void iv_getaddrinfo_cancel(struct iv_getaddrinfo *ig) { struct iv_getaddrinfo_task *t = ig->task; ig->task = NULL; t->ig = NULL; } ivykis-0.36.2/contrib/iv_getaddrinfo/iv_getaddrinfo.h000066400000000000000000000023611210744026200227010ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2011 Lennert Buytenhek * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __IV_GETADDRINFO_H #define __IV_GETADDRINFO_H #include #ifdef __cplusplus extern "C" { #endif struct iv_getaddrinfo { const char *node; const char *service; const struct addrinfo *hints; void *cookie; void (*handler)(void *cookie, int ret, struct addrinfo *res); void *task; }; int iv_getaddrinfo_submit(struct iv_getaddrinfo *ig); void iv_getaddrinfo_cancel(struct iv_getaddrinfo *ig); #ifdef __cplusplus } #endif #endif ivykis-0.36.2/contrib/iv_getaddrinfo/test.c000066400000000000000000000105411210744026200206660ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2011 Lennert Buytenhek * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #ifndef AI_ADDRCONFIG #define AI_ADDRCONFIG 0 #endif #ifndef AI_V4MAPPED #define AI_V4MAPPED 0 #endif static void got_results(void *_ig, int ret, struct addrinfo *res) { struct iv_getaddrinfo *ig = _ig; struct addrinfo *a; if (ret) { printf("%s: return code is %d\n", ig->node, ret); free(ig); return; } a = res; while (a != NULL) { #ifdef VERBOSE int flags; printf("\n"); printf("address record:\n"); printf("ai_flags ="); flags = a->ai_flags; if (flags & AI_PASSIVE) { printf(" AI_PASSIVE"); flags &= ~AI_PASSIVE; } if (flags & AI_CANONNAME) { printf(" AI_CANONNAME"); flags &= ~AI_CANONNAME; } if (flags & AI_NUMERICHOST) { printf(" AI_NUMERICHOST"); flags &= ~AI_NUMERICHOST; } if (flags & AI_V4MAPPED) { printf(" AI_V4MAPPED"); flags &= ~AI_V4MAPPED; } if (flags & AI_ALL) { printf(" AI_ALL"); flags &= ~AI_ALL; } if (flags & AI_ADDRCONFIG) { printf(" AI_ADDRCONFIG"); flags &= ~AI_ADDRCONFIG; } if (flags & AI_IDN) { printf(" AI_IDN"); flags &= ~AI_IDN; } if (flags & AI_CANONIDN) { printf(" AI_CANONIDN"); flags &= ~AI_CANONIDN; } if (flags & AI_IDN_ALLOW_UNASSIGNED) { printf(" AI_IDN_ALLOW_UNASSIGNED"); flags &= ~AI_IDN_ALLOW_UNASSIGNED; } if (flags & AI_IDN_USE_STD3_ASCII_RULES) { printf(" AI_IDN_USE_STD3_ASCII_RULES"); flags &= ~AI_IDN_USE_STD3_ASCII_RULES; } if (flags & AI_NUMERICSERV) { printf(" AI_NUMERICSERV"); flags &= ~AI_NUMERICSERV; } if (flags) printf(" %x", flags); printf("\n"); printf("ai_family = "); if (a->ai_family == PF_INET) printf("PF_INET\n"); else if (a->ai_family == PF_INET6) printf("PF_INET6\n"); else printf("%d\n", a->ai_family); printf("ai_socktype = "); if (a->ai_socktype == SOCK_STREAM) printf("SOCK_STREAM\n"); else if (a->ai_socktype == SOCK_DGRAM) printf("SOCK_DGRAM\n"); else printf("%d\n", a->ai_socktype); printf("ai_protocol = "); if (a->ai_protocol == IPPROTO_TCP) printf("IPPROTO_TCP\n"); else if (a->ai_protocol == IPPROTO_UDP) printf("IPPROTO_UDP\n"); else printf("%d\n", a->ai_protocol); printf("ai_addr = "); #endif printf("%s: ", ig->node); if (a->ai_addr->sa_family == AF_INET) { struct sockaddr_in *in; char name[64]; in = (struct sockaddr_in *)a->ai_addr; inet_ntop(AF_INET, &in->sin_addr, name, sizeof(name)); printf("%s\n", name); #ifndef __hpux__ } else if (a->ai_addr->sa_family == AF_INET6) { struct sockaddr_in6 *in; char name[64]; in = (struct sockaddr_in6 *)a->ai_addr; inet_ntop(AF_INET6, &in->sin6_addr, name, sizeof(name)); printf("%s\n", name); #endif } else { printf("unknown address family\n"); } #ifdef VERBOSE printf("ai_canonname = %s\n", a->ai_canonname); #endif a = a->ai_next; } freeaddrinfo(res); free(ig); } int main(int argc, char *argv[]) { struct addrinfo hints; int i; iv_init(); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; hints.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED; for (i = 1; i < argc; i++) { struct iv_getaddrinfo *ig; ig = malloc(sizeof(*ig)); if (ig == NULL) break; memset(ig, 0, sizeof(*ig)); ig->node = argv[i]; ig->service = NULL; ig->hints = &hints; ig->cookie = ig; ig->handler = got_results; iv_getaddrinfo_submit(ig); } iv_main(); iv_deinit(); return 0; } ivykis-0.36.2/contrib/kojines/000077500000000000000000000000001210744026200162205ustar00rootroot00000000000000ivykis-0.36.2/contrib/kojines/00README.txt000066400000000000000000000027641210744026200200670ustar00rootroot00000000000000 kojines is an application that accepts connections forwarded to it by the iptables REDIRECT target, and forwards them to a remote SOCKS5 proxy, using the original destination address of the REDIRECTed connection as the destination address in the SOCKS5 proxy request. Example setup: 1. Set up a SOCKS5 proxy. For example, using ssh, run ssh with the "-D 1080" argument (or add 'DynamicForward 0.0.0.0:1080' in the config file for the host you are ssh'ing to). 2. Start kojines. 3. Forward connections to kojines by adding an iptables rule to REDIRECT those connections to localhost port 63636 (which is the default address:port combination that kojines listens on). For example, to forward all connections to 1.2.3.4 port 80 (TCP) over the SOCKS5 proxy, do: iptables -t nat -A OUTPUT -d 1.2.3.4 -p tcp --dport 80 -j REDIRECT --to-ports 63636 Now if a connection is made to 1.2.3.4:80, it will be redirected to localhost:63636, where kojines will pick it up, issue a SO_ORIGINAL_DST ioctl on it to find the original destination address, get 1.2.3.4:80 back from that ioctl, connect to 127.0.0.1:1080 (the ssh process you started earlier), send a SOCKS5 open request for the remote address 1.2.3.4:80 to 127.0.0.1:1080, and once the SOCKS5 connection establishes, splice the two TCP connections together. There is currently no run-time (config file or command line option) method to change the listening address and SOCKS5 proxy address -- you'll have to edit main.c for now. ivykis-0.36.2/contrib/kojines/Makefile.am000066400000000000000000000003571210744026200202610ustar00rootroot00000000000000AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include LDADD = $(top_builddir)/src/libivykis.la noinst_PROGRAMS = kojines kojines_SOURCES = main.c kojines.c noinst_HEADERS = kojines.h EXTRA_DIST = 00README.txt ivykis-0.36.2/contrib/kojines/kojines.c000066400000000000000000000215221210744026200200300ustar00rootroot00000000000000/* * kojines - Transparent SOCKS connection forwarder. * Copyright (C) 2006, 2007, 2009, 2011 Lennert Buytenhek * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include "kojines.h" struct kojine { struct iv_list_head list; struct iv_fd client_fd; struct iv_fd server_fd; struct sockaddr_in orig_dst; int connected; union { struct { struct iv_timer connect_timeout; int buf_length; uint8_t buf[10]; }; struct { struct iv_fd_pump cs; struct iv_fd_pump sc; }; }; }; static void __kojine_kill(struct kojine *k) { iv_list_del(&k->list); iv_fd_unregister(&k->client_fd); close(k->client_fd.fd); iv_fd_unregister(&k->server_fd); close(k->server_fd.fd); free(k); } static void kojine_kill(struct kojine *k) { if (!k->connected) { iv_timer_unregister(&k->connect_timeout); } else { iv_fd_pump_destroy(&k->cs); iv_fd_pump_destroy(&k->sc); } __kojine_kill(k); } static void cs_pump(void *_k) { struct kojine *k = (struct kojine *)_k; int ret; ret = iv_fd_pump_pump(&k->cs); if (ret < 0) { kojine_kill(k); return; } if (ret == 0) { if (!iv_fd_pump_is_done(&k->sc)) shutdown(k->server_fd.fd, SHUT_WR); else kojine_kill(k); } } static void cs_set_bands(void *_k, int pollin, int pollout) { struct kojine *k = (struct kojine *)_k; iv_fd_set_handler_in(&k->client_fd, pollin ? cs_pump : NULL); iv_fd_set_handler_out(&k->server_fd, pollout ? cs_pump : NULL); } static void sc_pump(void *_k) { struct kojine *k = (struct kojine *)_k; int ret; ret = iv_fd_pump_pump(&k->sc); if (ret < 0) { kojine_kill(k); return; } if (ret == 0) { if (!iv_fd_pump_is_done(&k->cs)) shutdown(k->client_fd.fd, SHUT_WR); else kojine_kill(k); } } static void sc_set_bands(void *_k, int pollin, int pollout) { struct kojine *k = (struct kojine *)_k; iv_fd_set_handler_in(&k->server_fd, pollin ? sc_pump : NULL); iv_fd_set_handler_out(&k->client_fd, pollout ? sc_pump : NULL); } static void got_server_connect_reply(void *_k) { struct kojine *k = (struct kojine *)_k; int space; int ret; space = 10 - k->buf_length; if (!space) { kojine_kill(k); return; } ret = read(k->server_fd.fd, k->buf + k->buf_length, space); if (ret <= 0) { if (ret == 0 || errno != EAGAIN) kojine_kill(k); return; } k->buf_length += ret; if (k->buf_length < 10) return; iv_fd_set_handler_in(&k->server_fd, NULL); if (memcmp(k->buf, "\x05\x00", 2)) { kojine_kill(k); return; } iv_timer_unregister(&k->connect_timeout); k->connected = 1; IV_FD_PUMP_INIT(&k->cs); k->cs.from_fd = k->client_fd.fd; k->cs.to_fd = k->server_fd.fd; k->cs.cookie = k; k->cs.set_bands = cs_set_bands; k->cs.flags = 0; iv_fd_pump_init(&k->cs); IV_FD_PUMP_INIT(&k->sc); k->sc.from_fd = k->server_fd.fd; k->sc.to_fd = k->client_fd.fd; k->sc.cookie = k; k->sc.set_bands = sc_set_bands; k->sc.flags = 0; iv_fd_pump_init(&k->sc); } static void got_server_auth_reply(void *_k) { struct kojine *k = (struct kojine *)_k; int space; int ret; uint8_t buf[10]; space = 2 - k->buf_length; if (!space) { kojine_kill(k); return; } ret = read(k->server_fd.fd, k->buf + k->buf_length, space); if (ret <= 0) { if (ret == 0 || errno != EAGAIN) kojine_kill(k); return; } k->buf_length += ret; if (k->buf_length < 2) return; if (memcmp(k->buf, "\x05\x00", 2)) { kojine_kill(k); return; } buf[0] = 0x05; // SOCKSv5 buf[1] = 0x01; // CONNECT buf[2] = 0x00; // reserved buf[3] = 0x01; // IPv4 buf[4] = (ntohl(k->orig_dst.sin_addr.s_addr) >> 24) & 0xff; buf[5] = (ntohl(k->orig_dst.sin_addr.s_addr) >> 16) & 0xff; buf[6] = (ntohl(k->orig_dst.sin_addr.s_addr) >> 8) & 0xff; buf[7] = ntohl(k->orig_dst.sin_addr.s_addr) & 0xff; buf[8] = (ntohs(k->orig_dst.sin_port) >> 8) & 0xff; buf[9] = ntohs(k->orig_dst.sin_port) & 0xff; if (write(k->server_fd.fd, buf, 10) != 10) { kojine_kill(k); return; } iv_fd_set_handler_in(&k->server_fd, got_server_connect_reply); k->buf_length = 0; } static void got_server_connect(void *_k) { struct kojine *k = (struct kojine *)_k; socklen_t len; int ret; len = sizeof(ret); if (getsockopt(k->server_fd.fd, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { fprintf(stderr, "got_server_connect: error %d while " "getsockopt(SO_ERROR)\n", errno); abort(); } if (ret) { if (ret != EINPROGRESS) kojine_kill(k); return; } /* * SOCKSv5 (0x05), * 1 authentication method (0x01): * no authentication (0x00). */ if (write(k->server_fd.fd, "\x05\x01\x00", 3) != 3) { kojine_kill(k); return; } iv_fd_set_handler_in(&k->server_fd, got_server_auth_reply); iv_fd_set_handler_out(&k->server_fd, NULL); k->buf_length = 0; } static void server_connect_timeout(void *_k) { struct kojine *k = (struct kojine *)_k; __kojine_kill(k); } static void set_keepalive(int fd) { int yes; yes = 1; if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) < 0) { fprintf(stderr, "set_keepalive: error %d while " "setsockopt(SO_KEEPALIVE)\n", errno); abort(); } } static void got_kojine(void *_ki) { struct kojines_instance *ki = (struct kojines_instance *)_ki; struct sockaddr_in src; struct sockaddr_in orig_dst; struct sockaddr_in nexthop; struct kojine *k; socklen_t len; int client; int server; int ret; len = sizeof(src); client = accept(ki->listen_fd.fd, (struct sockaddr *)&src, &len); if (client < 0) { if (errno != EAGAIN && errno != ECONNABORTED) { fprintf(stderr, "got_kojine: error %d\n", errno); abort(); } return; } len = sizeof(orig_dst); if (getsockopt(client, SOL_IP, SO_ORIGINAL_DST, &orig_dst, &len) < 0) { close(client); return; } if (!ki->get_nexthop(ki->cookie, &nexthop, &src, &orig_dst)) { close(client); return; } set_keepalive(client); server = socket(AF_INET, SOCK_STREAM, 0); if (server < 0) { close(client); return; } k = malloc(sizeof(*k)); if (k == NULL) { close(server); close(client); return; } set_keepalive(server); iv_list_add_tail(&k->list, &ki->kojines); IV_FD_INIT(&k->client_fd); k->client_fd.fd = client; k->client_fd.cookie = (void *)k; iv_fd_register(&k->client_fd); IV_FD_INIT(&k->server_fd); k->server_fd.fd = server; k->server_fd.cookie = (void *)k; k->server_fd.handler_out = got_server_connect; iv_fd_register(&k->server_fd); k->orig_dst = orig_dst; k->connected = 0; IV_TIMER_INIT(&k->connect_timeout); k->connect_timeout.cookie = (void *)k; k->connect_timeout.handler = server_connect_timeout; iv_validate_now(); k->connect_timeout.expires = iv_now; k->connect_timeout.expires.tv_sec += 120; iv_timer_register(&k->connect_timeout); ret = connect(k->server_fd.fd, (struct sockaddr *)&nexthop, sizeof(nexthop)); if (ret == 0 || errno != EINPROGRESS) got_server_connect((void *)k); } int kojines_instance_register(struct kojines_instance *ki) { struct sockaddr_in listen_addr; int fd; int yes; fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) return 0; yes = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { close(fd); return 0; } listen_addr.sin_family = AF_INET; listen_addr.sin_port = htons(ki->listen_port); listen_addr.sin_addr.s_addr = htonl(0x7f000001); if (bind(fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) < 0) { close(fd); return 0; } if (listen(fd, 100) < 0) { close(fd); return 0; } IV_FD_INIT(&ki->listen_fd); ki->listen_fd.fd = fd; ki->listen_fd.cookie = (void *)ki; ki->listen_fd.handler_in = got_kojine; iv_fd_register(&ki->listen_fd); INIT_IV_LIST_HEAD(&ki->kojines); return 1; } void kojines_instance_unregister(struct kojines_instance *ki) { struct iv_list_head *ilh; struct iv_list_head *ilh2; iv_fd_unregister(&ki->listen_fd); close(ki->listen_fd.fd); iv_list_for_each_safe (ilh, ilh2, &ki->kojines) { struct kojine *k; k = iv_list_entry(ilh, struct kojine, list); kojine_kill(k); } } void kojines_instance_detach(struct kojines_instance *ki) { struct iv_list_head *ilh; struct iv_list_head *ilh2; iv_fd_unregister(&ki->listen_fd); close(ki->listen_fd.fd); iv_list_for_each_safe (ilh, ilh2, &ki->kojines) iv_list_del_init(ilh); } ivykis-0.36.2/contrib/kojines/kojines.h000066400000000000000000000026661210744026200200450ustar00rootroot00000000000000/* * kojines - Transparent SOCKS connection forwarder. * Copyright (C) 2006, 2007, 2009 Lennert Buytenhek * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __KOJINES_H #define __KOJINES_H #include #include #include #ifdef __cplusplus extern "C" { #endif struct kojines_instance { int listen_port; void *cookie; int (*get_nexthop)(void *cookie, struct sockaddr_in *nexthop, struct sockaddr_in *src, struct sockaddr_in *origdst); struct iv_fd listen_fd; struct iv_list_head kojines; }; int kojines_instance_register(struct kojines_instance *); void kojines_instance_unregister(struct kojines_instance *); void kojines_instance_detach(struct kojines_instance *); #ifdef __cplusplus } #endif #endif ivykis-0.36.2/contrib/kojines/main.c000066400000000000000000000035121210744026200173110ustar00rootroot00000000000000/* * kojines - Transparent SOCKS connection forwarder. * Copyright (C) 2006, 2007, 2009 Lennert Buytenhek * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include "kojines.h" static struct kojines_instance ki; static struct iv_signal sigusr1; static void got_sigusr1(void *_dummy) { kojines_instance_detach(&ki); iv_signal_unregister(&sigusr1); } /* * Given src and origdst addresses of a connection attempt, determine * which SOCKS proxy (nexthop) to forward this connection to. */ static int get_nexthop(void *cookie, struct sockaddr_in *nexthop, struct sockaddr_in *src, struct sockaddr_in *origdst) { nexthop->sin_family = AF_INET; nexthop->sin_port = htons(1080); nexthop->sin_addr.s_addr = htonl(0x7f000001); return 1; } int main() { iv_init(); ki.listen_port = 63636; ki.cookie = NULL; ki.get_nexthop = get_nexthop; if (kojines_instance_register(&ki)) { IV_SIGNAL_INIT(&sigusr1); sigusr1.signum = SIGUSR1; sigusr1.flags = 0; sigusr1.cookie = NULL; sigusr1.handler = got_sigusr1; iv_signal_register(&sigusr1); iv_main(); } iv_deinit(); return 0; } ivykis-0.36.2/libivykis.posix.ver000066400000000000000000000031051210744026200170010ustar00rootroot00000000000000IVYKIS_0.29 { global: # iv_avl iv_avl_tree_insert; iv_avl_tree_delete; iv_avl_tree_next; iv_avl_tree_prev; # iv_event iv_event_register; iv_event_unregister; iv_event_post; # iv_event_raw iv_event_raw_register; iv_event_raw_unregister; iv_event_raw_post; # iv_fd iv_poll_method_name; IV_FD_INIT; iv_fd_register; iv_fd_register_try; iv_fd_unregister; iv_fd_registered; iv_fd_set_handler_in; iv_fd_set_handler_out; iv_fd_set_handler_err; # iv_fd_pump iv_fd_pump_init; iv_fd_pump_destroy; iv_fd_pump_pump; iv_fd_pump_is_done; # iv_inotify iv_inotify_register; iv_inotify_unregister; iv_inotify_watch_register; iv_inotify_watch_unregister; # iv_main iv_init; iv_inited; iv_quit; iv_main; iv_deinit; # iv_popen iv_popen_request_submit; iv_popen_request_close; # iv_signal iv_signal_register; iv_signal_unregister; # iv_task IV_TASK_INIT; iv_task_register; iv_task_unregister; iv_task_registered; # iv_thread iv_thread_create; iv_thread_set_debug_state; iv_thread_list_children; # iv_timer iv_invalidate_now; iv_validate_now; __iv_now_location; IV_TIMER_INIT; iv_timer_register; iv_timer_unregister; iv_timer_registered; # iv_tls iv_tls_user_register; iv_tls_user_ptr; # iv_wait iv_wait_interest_register; iv_wait_interest_register_spawn; iv_wait_interest_unregister; iv_wait_interest_kill; # iv_work iv_work_pool_create; iv_work_pool_put; iv_work_pool_submit_work; local: *; }; IVYKIS_0.30 { # iv_fatal iv_fatal; iv_set_fatal_msg_handler; } IVYKIS_0.29; IVYKIS_0.33 { # iv_thread iv_thread_get_id; } IVYKIS_0.30; ivykis-0.36.2/libivykis.win32.ver000066400000000000000000000017441210744026200166100ustar00rootroot00000000000000IVYKIS { global: # iv_avl iv_avl_tree_insert; iv_avl_tree_delete; iv_avl_tree_next; iv_avl_tree_prev; # iv_event iv_event_register; iv_event_unregister; iv_event_post; # iv_event_raw iv_event_raw_register; iv_event_raw_unregister; iv_event_raw_post; # iv_fatal iv_fatal; iv_set_fatal_msg_handler; # iv_handle IV_HANDLE_INIT; iv_handle_register; iv_handle_unregister; iv_handle_registered; iv_handle_set_handler; # iv_main iv_init; iv_inited; iv_quit; iv_main; iv_deinit; # iv_task IV_TASK_INIT; iv_task_register; iv_task_unregister; iv_task_registered; # iv_thread iv_thread_create; iv_thread_set_debug_state; iv_thread_get_id; iv_thread_list_children; # iv_timer iv_invalidate_now; iv_validate_now; __iv_now_location; IV_TIMER_INIT; iv_timer_register; iv_timer_unregister; iv_timer_registered; # iv_tls iv_tls_user_register; iv_tls_user_ptr; # iv_work iv_work_pool_create; iv_work_pool_put; iv_work_pool_submit_work; local: *; }; ivykis-0.36.2/man3/000077500000000000000000000000001210744026200137545ustar00rootroot00000000000000ivykis-0.36.2/man3/IV_EVENT_INIT.3000066400000000000000000000000241210744026200161360ustar00rootroot00000000000000.so man3/iv_event.3 ivykis-0.36.2/man3/IV_EVENT_RAW_INIT.3000066400000000000000000000000301210744026200166440ustar00rootroot00000000000000.so man3/iv_event_raw.3 ivykis-0.36.2/man3/IV_FD_PUMP_INIT.3000066400000000000000000000000261210744026200164110ustar00rootroot00000000000000.so man3/iv_fd_pump.3 ivykis-0.36.2/man3/IV_INOTIFY_INIT.3000066400000000000000000000000261210744026200164000ustar00rootroot00000000000000.so man3/iv_inotify.3 ivykis-0.36.2/man3/IV_INOTIFY_WATCH_INIT.3000066400000000000000000000000261210744026200173260ustar00rootroot00000000000000.so man3/iv_inotify.3 ivykis-0.36.2/man3/IV_POPEN_REQUEST_INIT.3000066400000000000000000000000241210744026200173460ustar00rootroot00000000000000.so man3/iv_popen.3 ivykis-0.36.2/man3/IV_SIGNAL_INIT.3000066400000000000000000000000251210744026200162330ustar00rootroot00000000000000.so man3/iv_signal.3 ivykis-0.36.2/man3/IV_WAIT_INTEREST_INIT.3000066400000000000000000000000231210744026200173350ustar00rootroot00000000000000.so man3/iv_wait.3 ivykis-0.36.2/man3/IV_WORK_ITEM_INIT.3000066400000000000000000000000231210744026200166540ustar00rootroot00000000000000.so man3/iv_work.3 ivykis-0.36.2/man3/IV_WORK_POOL_INIT.3000066400000000000000000000000231210744026200166670ustar00rootroot00000000000000.so man3/iv_work.3 ivykis-0.36.2/man3/Makefile.am000066400000000000000000000040711210744026200160120ustar00rootroot00000000000000man3_MANS = iv_deinit.3 \ iv_event.3 \ IV_EVENT_INIT.3 \ iv_event_post.3 \ iv_event_raw.3 \ IV_EVENT_RAW_INIT.3 \ iv_event_raw_post.3 \ iv_event_raw_register.3 \ iv_event_raw_unregister.3 \ iv_event_register.3 \ iv_event_unregister.3 \ iv_examples.3 \ iv_fatal.3 \ iv_fd.3 \ iv_fd_pump.3 \ iv_fd_pump_destroy.3 \ IV_FD_PUMP_INIT.3 \ iv_fd_pump_init.3 \ iv_fd_pump_is_done.3 \ iv_fd_pump_pump.3 \ iv_fd_register.3 \ iv_fd_registered.3 \ iv_fd_register_try.3 \ iv_fd_set_handler_err.3 \ iv_fd_set_handler_in.3 \ iv_fd_set_handler_out.3 \ iv_fd_unregister.3 \ iv_init.3 \ iv_inited.3 \ iv_invalidate_now.3 \ iv_main.3 \ iv_popen.3 \ iv_popen_request_close.3 \ IV_POPEN_REQUEST_INIT.3 \ iv_popen_request_submit.3 \ iv_quit.3 \ iv_set_fatal_msg_handler.3 \ iv_signal.3 \ IV_SIGNAL_INIT.3 \ iv_signal_register.3 \ iv_signal_unregister.3 \ iv_task.3 \ iv_task_register.3 \ iv_task_registered.3 \ iv_task_unregister.3 \ iv_thread.3 \ iv_thread_create.3 \ iv_thread_set_debug_state.3 \ iv_time.3 \ iv_timer.3 \ iv_timer_register.3 \ iv_timer_registered.3 \ iv_timer_unregister.3 \ iv_tls.3 \ iv_tls_user_ptr.3 \ iv_tls_user_register.3 \ iv_validate_now.3 \ iv_wait.3 \ IV_WAIT_INTEREST_INIT.3 \ iv_wait_interest_register.3 \ iv_wait_interest_register_spawn.3 \ iv_wait_interest_unregister.3 \ iv_work.3 \ IV_WORK_ITEM_INIT.3 \ iv_work_pool_create.3 \ IV_WORK_POOL_INIT.3 \ iv_work_pool_put.3 \ iv_work_pool_submit_work.3 \ ivykis.3 if HAVE_INOTIFY man3_MANS += iv_inotify.3 \ IV_INOTIFY_INIT.3 \ iv_inotify_register.3 \ iv_inotify_unregister.3 \ IV_INOTIFY_WATCH_INIT.3 \ iv_inotify_watch_register.3 \ iv_inotify_watch_unregister.3 endif EXTRA_DIST = ${man3_MANS} ivykis-0.36.2/man3/iv_deinit.3000066400000000000000000000000231210744026200160050ustar00rootroot00000000000000.so man3/iv_init.3 ivykis-0.36.2/man3/iv_event.3000066400000000000000000000047051210744026200156650ustar00rootroot00000000000000.\" This man page is Copyright (C) 2010 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_event 3 2010-09-03 "ivykis" "ivykis programmer's manual" .SH NAME IV_EVENT_INIT, iv_event_register, iv_event_unregister, iv_event_post \- manage ivykis objects for event notification .SH SYNOPSIS .B #include .sp .nf struct iv_event { void *cookie; void (*handler)(void *); }; .fi .sp .BI "int IV_EVENT_INIT(struct iv_event *" this ");" .br .BI "int iv_event_register(struct iv_event *" this ");" .br .BI "void iv_event_unregister(struct iv_event *" this ");" .br .BI "void iv_event_post(struct iv_event *" this ");" .br .SH DESCRIPTION .B iv_event provides a way for delivering events to .BR ivykis (3) recipients across thread boundaries. .PP The intended event recipient calls .B IV_EVENT_INIT on a .B struct iv_event object, fills in .B ->cookie and .B ->handler, and then calls .B iv_event_register on the object. .PP To generate an event, call .B iv_event_post on the previously initialized .B struct iv_event object. This will cause the callback specified by .B ->handler to be called in the thread that the .B struct iv_event object was registered in, with .B ->cookie as its sole argument. .PP To deinitialize a .B struct iv_event object, call .B iv_event_unregister from the same thread that .B iv_event_register was called from on that object. .PP It is permitted to unregister a .B struct iv_event object from any ivykis callback function in the thread it was registered in, including from a callback function triggered by this object, and it is permitted to free the memory corresponding to an unregistered object from its own callback function. .PP .B iv_event_post can be called from the same thread that .B iv_event_register was called from, or from a different thread within the same process, but can not be called from a different process, and can not be called from signal handlers. If you need this functionality, look at .BR iv_event_raw (3). .PP Internally, .B iv_event is implemented as a wrapper around .BR iv_event_raw (3), and multiplexes multiple .B struct iv_event objects over per-thread .B struct iv_event_raw objects, to save file descriptors and kernel resources. .PP .SH "SEE ALSO" .BR ivykis (3), .BR iv_event_raw (3) ivykis-0.36.2/man3/iv_event_post.3000066400000000000000000000000241210744026200167200ustar00rootroot00000000000000.so man3/iv_event.3 ivykis-0.36.2/man3/iv_event_raw.3000066400000000000000000000060371210744026200165360ustar00rootroot00000000000000.\" This man page is Copyright (C) 2010 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_event_raw 3 2010-09-02 "ivykis" "ivykis programmer's manual" .SH NAME IV_EVENT_RAW_INIT, iv_event_raw_register, iv_event_raw_unregister, iv_event_raw_post \- manage ivykis objects for event notification .SH SYNOPSIS .B #include .sp .nf struct iv_event_raw { void *cookie; void (*handler)(void *); }; .fi .sp .BI "void IV_EVENT_RAW_INIT(struct iv_event_raw *" this ");" .br .BI "int iv_event_raw_register(struct iv_event_raw *" this ");" .br .BI "void iv_event_raw_unregister(struct iv_event_raw *" this ");" .br .BI "void iv_event_raw_post(struct iv_event_raw *" this ");" .br .SH DESCRIPTION .B iv_event_raw provides a way for delivering events to .BR ivykis (3) recipients across thread and process boundaries. .PP The intended event recipient calls .B IV_EVENT_RAW_INIT on a .B struct iv_event_raw object, fills in .B ->cookie and .B ->handler, and then calls .B iv_event_raw_register on the object. .PP To generate an event, call .B iv_event_raw_post on the previously initialized .B struct iv_event_raw object. This will cause the callback specified by .B ->handler to be called in the thread that the .B struct iv_event_raw object was registered in, with .B ->cookie as its sole argument. .PP To deinitialize a .B struct iv_event_raw object, call .B iv_event_raw_unregister from the same thread that .B iv_event_raw_register was called from on that object. .PP It is permitted to unregister a .B struct iv_event_raw object from any ivykis callback function in the thread it was registered in, including from a callback function triggered by this object, and it is permitted to free the memory corresponding to an unregistered object from its own callback function. .PP .B iv_event_raw_post can be called from the same thread that .B iv_event_raw_register was called from, from a different thread in the same process, or even from a different process, and can safely be called from signal handlers. .PP If posting an event only ever needs to be done from within the same process, see .BR iv_event (3) for a lighter-weight alternative to .B iv_event_raw. .PP Internally, .B iv_event_raw is implemented by registering a file descriptor (a struct .BR iv_fd (3)) with the recipient thread's ivykis event loop, and by causing that file descriptor to become readable upon a call to .B iv_event_raw_post. .PP If .BR eventfd (2) is available, it will be used to procure the abovementioned file descriptor. If not, .B iv_event_raw will fall back to .BR pipe (2) as the source of its file descriptors. .BR eventfd (2) is preferred as it requires only one file descriptor table entry (while .BR pipe (2) requires two), and has much less kernel overhead than .BR pipe (2) has. .SH "SEE ALSO" .BR ivykis (3), .BR iv_event (3), .BR eventfd (2), .BR pipe (2) ivykis-0.36.2/man3/iv_event_raw_post.3000066400000000000000000000000301210744026200175660ustar00rootroot00000000000000.so man3/iv_event_raw.3 ivykis-0.36.2/man3/iv_event_raw_register.3000066400000000000000000000000301210744026200204250ustar00rootroot00000000000000.so man3/iv_event_raw.3 ivykis-0.36.2/man3/iv_event_raw_unregister.3000066400000000000000000000000301210744026200207700ustar00rootroot00000000000000.so man3/iv_event_raw.3 ivykis-0.36.2/man3/iv_event_register.3000066400000000000000000000000241210744026200175570ustar00rootroot00000000000000.so man3/iv_event.3 ivykis-0.36.2/man3/iv_event_unregister.3000066400000000000000000000000241210744026200201220ustar00rootroot00000000000000.so man3/iv_event.3 ivykis-0.36.2/man3/iv_examples.3000066400000000000000000000260461210744026200163640ustar00rootroot00000000000000.\" This man page is Copyright (C) 2003 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH ivykis 3 2003-03-29 "ivykis" "ivykis programmer's manual" .SH NAME iv_examples \- ivykis examples .SH EXAMPLE ivykis is initialised by calling .BR iv_init (3). This function is the first function to call when dealing with ivykis -- it has to be called before registering file descriptors or timers. .PP The ivykis main event loop is started by calling .BR iv_main (3). This function generally does not return, except when .BR iv_quit (3) is called somewhere during execution of the program. .PP An application asks ivykis to monitor a certain file descriptor by filling out a structure of type 'struct iv_fd' with a file descriptor number and a callback function, and calling the function iv_fd_register. .PP The first example program waits for data from standard input, and writes a message to standard out whenever something is received: .PP .nf #include #include #include struct iv_fd fd_stdin; static void callback(void *dummy) { char buf[1024]; int len; len = read(fd_stdin.fd, buf, sizeof(buf)); if (len <= 0) { if (len < 0) { if (errno == EAGAIN) return; perror("read"); } exit(1); } printf("read %d bytes of data from stdin\\n", len); } int main() { iv_init(); IV_FD_INIT(&fd_stdin); fd_stdin.fd = 0; fd_stdin.handler_in = callback; iv_fd_register(&fd_stdin); iv_main(); iv_deinit(); return 0; } .fi .PP The application is responsible for memory management of 'struct iv_fd's passed to ivykis. For example, it should not free memory that contains such structures that are still registered with ivykis (i.e. haven't had iv_fd_unregister called on them). .PP iv_fd_register transparently sets the passed file descriptor to nonblocking mode, in anticipation of its future usage. .PP File descriptor callbacks are called in a level-triggered fashion. Therefore, the way of dealing with fd_stdin in the example callback function is safe. In case there arrives data between read and detecting EAGAIN, ivykis will re-call the callback function after it returns. Also, if there are more than 1024 bytes waiting in the input buffer, ivykis will re-call the callback function until all data from stdin have been drained. .SH "EXAMPLE 2" The second example accepts connections on TCP port 6667, and waits on each of the connections for data. When data is received on any connection, a message is printed to standard out. .PP .nf #include #include #include #include struct connection { struct iv_fd fd; /* other per-connection data goes here */ }; struct listening_socket { struct iv_fd fd; /* other per-listening socket data goes here */ }; static void connection_handler(void *_conn) { struct connection *conn = (struct connection *)_conn; char buf[1024]; int len; len = read(conn->fd.fd, buf, sizeof(buf)); if (len <= 0) { if (len < 0 && errno == EAGAIN) return; iv_fd_unregister(&conn->fd); close(conn->fd.fd); free(conn); return; } printf("got %d bytes of data from %p\\n", len, conn); } static void listening_socket_handler(void *_sock) { struct listening_socket *sock = (struct listening_socket *)_sock; struct sockaddr_in addr; socklen_t addrlen; struct connection *conn; int fd; addrlen = sizeof(addr); fd = accept(sock->fd.fd, (struct sockaddr *)&addr, &addrlen); if (fd < 0) { if (errno == EAGAIN) return; perror("accept"); exit(1); } conn = malloc(sizeof(*conn)); if (conn == NULL) { fprintf(stderr, "listening_socket_handler: memory allocation error, dropping connection"); close(fd); return; } IV_FD_INIT(&conn->fd); conn->fd.fd = fd; conn->fd.cookie = (void *)conn; conn->fd.handler_in = connection_handler; iv_fd_register(&conn->fd); } int main() { struct listening_socket s; struct sockaddr_in addr; int fd; fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); exit(1); } addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(6667); if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); exit(1); } if (listen(fd, 4) < 0) { perror("listen"); exit(1); } iv_init(); IV_FD_INIT(&s.fd); s.fd.fd = fd; s.fd.cookie = (void *)&s; s.fd.handler_in = listening_socket_handler; iv_fd_register(&s.fd); iv_main(); iv_deinit(); return 0; } .fi .PP As illustrated, it is possible to pass cookies into callback functions. This is useful for conveying information on which higher-level entity (such as 'connection' or 'listening socket') generated the event for which the callback was called. .PP Note how it is possible to unregister and even free a 'struct iv_fd' in its own callback function. There is logic in ivykis to deal with this case. .SH "EXAMPLE 3" This example extends the previous example by a per-connection timer that disconnects the client after too long a period of inactivity. Lines not present in example 2 or different than in example 2 are indicated by '//XXXX' in the right-hand margin. .PP .nf #include #include #include #include #define CONNECTION_TIMEOUT (10) struct connection { struct iv_fd fd; struct iv_timer disconnect_timeout; //XXXX /* other per-connection data goes here */ }; struct listening_socket { struct iv_fd fd; /* other per-listening socket data goes here */ }; static void connection_handler(void *_conn) { struct connection *conn = (struct connection *)_conn; char buf[1024]; int len; len = read(conn->fd.fd, buf, sizeof(buf)); if (len <= 0) { if (len < 0 && errno == EAGAIN) return; iv_timer_unregister(&conn->disconnect_timeout); //XXXX iv_fd_unregister(&conn->fd); close(conn->fd.fd); free(conn); return; } printf("got %d bytes of data from %p\\n", len, conn); iv_timer_unregister(&conn->disconnect_timeout); //XXXX iv_validate_now(); //XXXX conn->disconnect_timeout.expires = iv_now; //XXXX conn->disconnect_timeout.expires.tv_sec += CONNECTION_TIMEOUT;//XXXX iv_timer_register(&conn->disconnect_timeout); //XXXX } static void disconnect_timeout_expired(void *_conn) //XXXX { //XXXX struct connection *conn = (struct connection *)_conn; //XXXX iv_fd_unregister(&conn->fd); //XXXX close(conn->fd.fd); //XXXX free(conn); //XXXX } //XXXX static void listening_socket_handler(void *_sock) { struct listening_socket *sock = (struct listening_socket *)_sock; struct sockaddr_in addr; socklen_t addrlen; struct connection *conn; int fd; addrlen = sizeof(addr); fd = accept(sock->fd.fd, (struct sockaddr *)&addr, &addrlen); if (fd < 0) { if (errno == EAGAIN) return; perror("accept"); exit(1); } conn = malloc(sizeof(*conn)); if (conn == NULL) { fprintf(stderr, "listening_socket_handler: memory allocation error, dropping connection"); close(fd); return; } IV_FD_INIT(&conn->fd); conn->fd.fd = fd; conn->fd.cookie = (void *)conn; conn->fd.handler_in = connection_handler; iv_fd_register(&conn->fd); IV_TIMER_INIT(&conn->disconnect_timeout); //XXXX iv_validate_now(); //XXXX conn->disconnect_timeout.cookie = (void *)conn; //XXXX conn->disconnect_timeout.handler = disconnect_timeout_expired;//XXXX conn->disconnect_timeout.expires = iv_now; //XXXX conn->disconnect_timeout.expires.tv_sec += CONNECTION_TIMEOUT;//XXXX iv_timer_register(&conn->disconnect_timeout); //XXXX } int main() { struct listening_socket s; struct sockaddr_in addr; int fd; fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); exit(1); } addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(6667); if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); exit(1); } if (listen(fd, 4) < 0) { perror("listen"); exit(1); } iv_init(); IV_FD_INIT(&s.fd); s.fd.fd = fd; s.fd.cookie = (void *)&s; s.fd.handler_in = listening_socket_handler; iv_fd_register(&s.fd); iv_main(); iv_deinit(); return 0; } .fi .PP The global variable 'iv_now' contains the current time-of-day. However, it is updated lazily, and its contents might be stale at any given time. Before using it, .BR iv_validate_now (3) must be called. .SH "EXAMPLE 4" The fourth example demonstrates how to use a custom fatal error handler that does not write the message to syslog. .PP .nf #include #include static void fatal_error(const char *msg) { fprintf(stderr, "ivykis: FATAL ERROR: %s\\n", msg); } int main() { iv_init(); iv_set_fatal_msg_handler(fatal_error); iv_fatal("Programmatically triggered fatal error %d.", 42); printf("This code is never reached.\\n"); iv_deinit(); return 0; } .fi .PP This program will abort immediately, with the error message printed to the standard error stream. .SH "SEE ALSO" .BR ivykis (3), .BR iv_fatal (3), .BR iv_fd (3), .BR iv_timer (3), .BR iv_task (3), .BR iv_init (3), .BR iv_time (3) ivykis-0.36.2/man3/iv_fatal.3000066400000000000000000000025741210744026200156350ustar00rootroot00000000000000.\" This man page is Copyright (C) 2012 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_fatal 3 2012-06-18 "ivykis" "ivykis programmer's manual" .SH NAME iv_fatal, iv_set_fatal_msg_handler \- ivykis fatal error condition handling .SH SYNOPSIS .B #include .sp .BI "void iv_fatal(const char *" "fmt" ", ...);" .br .BI "void iv_set_fatal_msg_handler(void (*" "handler" ")(const char *" "msg" "));" .br .SH DESCRIPTION .B iv_fatal aborts the running program, after possibly emitting an error message. The .B fmt parameter is a .BR printf (3)-style format string, the message to be logged. .PP If no handler is set (the default), the formatted message will be sent to .BR syslog , with critical severity. Otherwise the .B handler as set by .B iv_set_fatal_msg_handler will be used instead. .PP .B iv_fatal is also used internally by ivykis, whenever a fatal situation is detected. .PP .B iv_set_fatal_msg_handler can be used to set an alternative (as opposed to .BR syslog ) function to call from .BR iv_fatal , and its argument should be a function that does not return, and takes a single string as argument \- the formatted error message. .SH "SEE ALSO" .BR ivykis (3), .BR iv_examples (3) ivykis-0.36.2/man3/iv_fd.3000066400000000000000000000132731210744026200151350ustar00rootroot00000000000000.\" This man page is Copyright (C) 2003, 2010 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_fd 3 2010-08-15 "ivykis" "ivykis programmer's manual" .SH NAME iv_fd_register, iv_fd_register_try, iv_fd_unregister, iv_fd_registered, iv_fd_set_handler_in, iv_fd_set_handler_err, iv_fd_set_handler_out \- deal with ivykis file descriptors .SH SYNOPSIS .B #include .sp .nf struct iv_fd { int fd; void *cookie; void (*handler_in)(void *); void (*handler_out)(void *); void (*handler_err)(void *); }; .fi .sp .BI "void IV_FD_INIT(struct iv_fd *" fd ");" .br .BI "void iv_fd_register(struct iv_fd *" fd ");" .br .BI "int iv_fd_register_try(struct iv_fd *" fd ");" .br .BI "void iv_fd_unregister(struct iv_fd *" fd ");" .br .BI "int iv_fd_registered(struct iv_fd *" fd ");" .br .BI "void iv_fd_set_handler_in(struct iv_fd *" fd ", void (*" handler ")(void *));" .br .BI "void iv_fd_set_handler_out(struct iv_fd *" fd ", void (*" handler ")(void *));" .br .BI "void iv_fd_set_handler_err(struct iv_fd *" fd ", void (*" handler ")(void *));" .br .SH DESCRIPTION The functions .B iv_fd_register and .B iv_fd_unregister register, respectively unregister, a file descriptor with the current thread's ivykis event loop. Calling .B iv_fd_registered on a file descriptor returns true if that file descriptor is currently registered with ivykis. .PP When a file descriptor that is registered with ivykis becomes ready for input or output, or an error condition occurs on that file descriptor, and a callback function for that event has been specified, that callback function will be called in the thread that the file descriptor was registered in. .PP And conversely, when a file descriptor that is already ready for input or output or already has an error condition set is registered with ivykis, and the corresponding callback function pointer is not NULL, the callback function will be called in the next iteration of the current thread's ivykis event loop. .PP Before a file descriptor is registered, it must have been initialised by calling .B IV_FD_INIT on it, and must have had its .B ->fd member field set to a valid OS file descriptor. The .B ->handler_in, ->handler_out and .B ->handler_err member fields point to callback functions that are to be called when the specified file descriptor becomes ready for input or output or an error condition occurs. If any handler function is set to .B NULL, it indicates that the application is not interested in being notified of the corresponding event. .PP An application is not allowed to change the .B ->fd member while a file descriptor is registered. .PP .B iv_fd_set_handler_in changes the callback function to be called when descriptor .B fd becomes ready for input. An application is not allowed to directly change the .B ->handler_in member after the file descriptor has been registered, this function has to be used instead. Conversely, it is not allowed to use this function before the file descriptor has been registered. .PP .B iv_fd_set_handler_out is analogous to .B iv_fd_set_handler_in, only it deals with the callback function for output readiness .B (->handler_out). .PP .B iv_fd_set_handler_err is analogous to .B iv_fd_set_handler_in and .B iv_fd_set_handler_out, only it deals with the callback function for error conditions .B (->handler_err). .PP When a handler function was NULL, and was set to a non-NULL value by calling .B iv_fd_set_handler_in, iv_fd_set_handler_out or .B iv_fd_set_handler_err, and the file descriptor was already ready for input or output, or already had an error condition set, an event is generated, and the specified callback function will be called in the next iteration of the current thread's event loop. The application does not need to poll the file descriptor to see if a condition was already raised. .PP Callback functions are passed a .B cookie value as their first and sole argument. If the application wishes to use this facility for transferring data to the callback function, it should set the .B ->cookie member of a file descriptor to a value of type .B void *. This value can be modified directly by the application at any time without calling a helper function. .PP When a file descriptor is registered with ivykis, it is transparently set to nonblocking mode, and configured to be closed on .BR exit (3). .PP An application is allowed to unregister a file descriptor from within any callback function, including callback functions triggered by that file descriptor itself, and even to free the memory corresponding to that file descriptor from any callback function, but a .B struct iv_fd can only be unregistered in the thread that it was registered from. .PP It is allowed to register the same underlying OS file descriptor in multiple threads, but a given .B struct iv_fd can only be registered in one thread at a time. .PP .B iv_fd_register does not return errors to the caller, and in case of an error while registering the file descriptor, for example if it isn't open or is unpollable, .BR abort (3) will be invoked. If it is not known whether registering the file descriptor with the kernel will be successful or not, use .B iv_fd_register_try instead, which is a variant on .B iv_fd_register which returns a nonzero value in case of a registration error. Since .B iv_fd_register_try disables various internal optimisations, it is recommended to use .B iv_fd_register whenever possible. .PP See .BR iv_examples (3) for programming examples. .SH "SEE ALSO" .BR ivykis (3), .BR iv_examples (3) ivykis-0.36.2/man3/iv_fd_pump.3000066400000000000000000000066151210744026200162000ustar00rootroot00000000000000.\" This man page is Copyright (C) 2012 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_fd_pump 3 2012-06-05 "ivykis" "ivykis programmer's manual" .SH NAME IV_FD_PUMP_INIT, iv_fd_pump_init, iv_fd_pump_destroy, iv_fd_pump_pump, iv_fd_pump_is_done \- pump data between file descriptors .SH SYNOPSIS .B #include .sp .nf struct iv_fd_pump { int from_fd; int to_fd; void *cookie; void (*set_bands)(void *cookie, int pollin, int pollout); unsigned int flags; }; .fi .sp .BI "void IV_FD_PUMP_INIT(struct iv_fd_pump *" this ");" .br .BI "void iv_fd_pump_init(struct iv_fd_pump *" this ");" .br .BI "void iv_fd_pump_destroy(struct iv_fd_pump *" this ");" .br .BI "int iv_fd_pump_pump(struct iv_fd_pump *" this ");" .br .BI "int iv_fd_pump_is_done(struct iv_fd_pump *" this ");" .br .SH DESCRIPTION .B iv_fd_pump provides a way for moving data between two file descriptors. .PP To set up .B iv_fd_pump for moving data, call .B IV_FD_PUMP_INIT on a .B struct iv_fd_pump object, fill in the .B ->from_fd, ->to_fd, ->cookie, ->set_bands and .B ->flags members, and then call .B iv_fd_pump_init on the object. .PP Conversely, to destroy a .B struct iv_fd_pump object, call .B iv_fd_pump_destroy. There are no restrictions on when this function can be called. .PP A call to .B iv_fd_pump_pump will attempt to move data from .B ->from_fd to .B ->to_fd via an internal buffer associated with the .B struct iv_fd_pump object. .PP During calls to .B iv_fd_pump_init, .B iv_fd_pump_destroy and .B iv_fd_pump_pump, the callback function specified by .B ->set_bands may be invoked (with .B ->cookie as its first argument), by which .B iv_fd_pump indicates under which circumstances it wishes for future invocations of .B iv_fd_pump_pump to be done. .PP If the .B pollin argument to .B ->set_bands is true, there is space left in the internal buffer (and we have not yet seen an end-of-file condition on input), and so you should call .B iv_fd_pump_pump again when there is a POLLIN condition on .B ->from_fd. .PP If the .B pollout argument to .B ->set_bands is true, there is data in the internal buffer that could not all be transferred to .B ->to_fd, and so you should call .B iv_fd_pump_pump again when there is a POLLOUT condition on .B ->to_fd. .PP If .B IV_FD_PUMP_FLAG_RELAY_EOF is set in .B ->flags, .B iv_fd_pump_pump will call .BR shutdown (2) on .B ->to_fd with .B SHUT_WR as its second argument upon seeing an end-of-file condition on .B ->from_fd (but only after all data from the internal buffer has been drained into .B ->to_fd first). .PP .B iv_fd_pump_pump will return \-1 if there was an error, 0 if we're done pumping data (meaning that an end-of-file condition was seen on the input file descriptor and that all data in the internal buffer has been drained into the output file descriptor), or 1 if there is more data left to be pumped. .PP .B iv_fd_pump_is_done will return a true value if iv_fd_pump_pump has previously returned 0, otherwise it will return false. .PP Internally, .B iv_fd_pump_pump will use .BR splice (2) if it is available, otherwise it will fall back to .BR read (2) and .BR write (2). .PP .SH "SEE ALSO" .BR ivykis (3), .BR splice (2) ivykis-0.36.2/man3/iv_fd_pump_destroy.3000066400000000000000000000000261210744026200177370ustar00rootroot00000000000000.so man3/iv_fd_pump.3 ivykis-0.36.2/man3/iv_fd_pump_init.3000066400000000000000000000000261210744026200172110ustar00rootroot00000000000000.so man3/iv_fd_pump.3 ivykis-0.36.2/man3/iv_fd_pump_is_done.3000066400000000000000000000000261210744026200176660ustar00rootroot00000000000000.so man3/iv_fd_pump.3 ivykis-0.36.2/man3/iv_fd_pump_pump.3000066400000000000000000000000261210744026200172270ustar00rootroot00000000000000.so man3/iv_fd_pump.3 ivykis-0.36.2/man3/iv_fd_register.3000066400000000000000000000000211210744026200170240ustar00rootroot00000000000000.so man3/iv_fd.3 ivykis-0.36.2/man3/iv_fd_register_try.3000066400000000000000000000000211210744026200177220ustar00rootroot00000000000000.so man3/iv_fd.3 ivykis-0.36.2/man3/iv_fd_registered.3000066400000000000000000000000211210744026200173350ustar00rootroot00000000000000.so man3/iv_fd.3 ivykis-0.36.2/man3/iv_fd_set_handler_err.3000066400000000000000000000000211210744026200203400ustar00rootroot00000000000000.so man3/iv_fd.3 ivykis-0.36.2/man3/iv_fd_set_handler_in.3000066400000000000000000000000211210744026200201560ustar00rootroot00000000000000.so man3/iv_fd.3 ivykis-0.36.2/man3/iv_fd_set_handler_out.3000066400000000000000000000000211210744026200203570ustar00rootroot00000000000000.so man3/iv_fd.3 ivykis-0.36.2/man3/iv_fd_unregister.3000066400000000000000000000000211210744026200173670ustar00rootroot00000000000000.so man3/iv_fd.3 ivykis-0.36.2/man3/iv_init.3000066400000000000000000000023301210744026200154770ustar00rootroot00000000000000.\" This man page is Copyright (C) 2003, 2010 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_init 3 2010-09-05 "ivykis" "ivykis programmer's manual" .SH NAME iv_init, iv_deinit, iv_inited \- initialise and deinitialise ivykis .SH SYNOPSIS .B #include .sp .BI "void iv_init(void);" .br .BI "void iv_deinit(void);" .br .BI "int iv_inited(void);" .br .SH DESCRIPTION .B iv_init initialises the current thread's ivykis event loop. .PP Each thread that wants to use ivykis must call .B iv_init before any other ivykis functions are called. .PP The very first call to .B iv_init in a process must run to completion before other threads are allowed to call .B iv_init, but subsequent calls to .B iv_init can be done concurrently. .PP .B iv_deinit frees all resources allocated by ivykis in this thread, and should be called before this thread exits. .PP .B iv_inited returns true if .B iv_init has been called in this thread. After .B iv_deinit is called, it will return false. .SH "SEE ALSO" .BR ivykis (3), .BR iv_examples (3) ivykis-0.36.2/man3/iv_inited.3000066400000000000000000000000231210744026200160050ustar00rootroot00000000000000.so man3/iv_init.3 ivykis-0.36.2/man3/iv_inotify.3000066400000000000000000000054641210744026200162300ustar00rootroot00000000000000.\" This man page is Copyright (C) 2009 Ronald Huizer. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_inotify 3 2009-02-07 "ivykis" "ivykis programmer's manual" .SH NAME IV_INOTIFY_INIT, iv_inotify_register, iv_inotify_unregister, IV_INOTIFY_WATCH_INIT, iv_inotify_watch_register, iv_inotify_watch_unregister \- ivykis .BR inotify (7) wrapper .SH SYNOPSIS .nf .B #include .sp .nf struct iv_inotify { }; .fi .sp .BI "void IV_INOTIFY_INIT(struct iv_inotify *" inotify ");" .br .BI "int iv_inotify_register(struct iv_inotify *" inotify "); .br .BI "void iv_inotify_unregister(struct iv_inotify *"inotify "); .br .nf .sp struct iv_inotify_watch { struct iv_inotify *inotify; const char *pathname; uint32_t mask; void *cookie; void (*handler)(void *, struct inotify_event *); }; .fi .sp .BI "void IV_INOTIFY_WATCH_INIT(struct iv_inotify_watch *" watch ");" .br .BI "int iv_inotify_watch_register(struct iv_inotify_watch *" watch ");" .br .BI "int iv_inotify_watch_unregister(struct iv_inotify_watch *" watch ");" .br .SH DESCRIPTION The .B iv_inotify_register function registers an .B iv_inotify instance with the .BR iv_inotify (3) module. The .B inotify parameter is a pointer to the .B iv_inotify structure to be registered. .PP The .B iv_inotify_unregister function unregisters an .B iv_inotify instance from the .BR iv_inotify (3) module. The .B inotify parameter is a pointer to the .B iv_inotify structure to be unregistered. .PP The .B iv_inotify_watch_register function adds a watch to the registered .B iv_inotify instance specified by the .B ->inotify member. .PP The .B iv_inotify_watch_unregister function removes a watch from the .BR iv_inotify instance specified by the .B ->inotify member. .PP In the .B iv_inotify_watch structure used in these functions, the .B ->pathname and .B ->mask members correspond to the members of struct inotify_watch as described in .BR inotify (7). .B ->handler is the event handler called when this watch triggers. The arguments to this handler function are the pointer stored in the .B ->cookie member of the .B iv_inotify_watch structure and a pointer to an inotify_event structure as described in .BR inotify (7). .SH "RETURN VALUE" .B iv_inotify_register and .B iv_inotify_watch_register return zero on success. On error, \-1 is returned, and errno is set appropriately. .SH "ERRORS" iv_inotify will return errors returned by .BR inotify_init (3) and .BR inotify_add_watch (3). .SH "SEE ALSO" .BR ivykis (3), .BR inotify (7), .BR inotify_init (3), .BR inotify_add_watch (3), .BR inotify_rm_watch (3) ivykis-0.36.2/man3/iv_inotify_register.3000066400000000000000000000000261210744026200201210ustar00rootroot00000000000000.so man3/iv_inotify.3 ivykis-0.36.2/man3/iv_inotify_unregister.3000066400000000000000000000000261210744026200204640ustar00rootroot00000000000000.so man3/iv_inotify.3 ivykis-0.36.2/man3/iv_inotify_watch_register.3000066400000000000000000000000261210744026200213070ustar00rootroot00000000000000.so man3/iv_inotify.3 ivykis-0.36.2/man3/iv_inotify_watch_unregister.3000066400000000000000000000000261210744026200216520ustar00rootroot00000000000000.so man3/iv_inotify.3 ivykis-0.36.2/man3/iv_invalidate_now.3000066400000000000000000000000231210744026200175340ustar00rootroot00000000000000.so man3/iv_time.3 ivykis-0.36.2/man3/iv_main.3000066400000000000000000000017411210744026200154650ustar00rootroot00000000000000.\" This man page is Copyright (C) 2003, 2010 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_main 3 2010-08-15 "ivykis" "ivykis programmer's manual" .SH NAME iv_main \- enter the ivykis main loop .SH SYNOPSIS .B #include .sp .BI "void iv_main(void);" .br .SH DESCRIPTION .B iv_main enters the current thread's ivykis main loop. .PP The ivykis main loop consists of checking the status of the registered file descriptors, timers and tasks, and either calling callback functions corresponding to active objects, or blocking until an event arrives. .PP Each thread that wants to use ivykis must individually call .B iv_main to enter the ivykis main loop -- but only after having called .BR iv_init (3) earlier. .SH "SEE ALSO" .BR ivykis (3), .BR iv_examples (3), .BR iv_quit (3) ivykis-0.36.2/man3/iv_popen.3000066400000000000000000000043521210744026200156630ustar00rootroot00000000000000.\" This man page is Copyright (C) 2010 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_popen 3 2010-09-04 "ivykis" "ivykis programmer's manual" .SH NAME IV_POPEN_REQUEST_INIT, iv_popen_request_submit, iv_popen_request_close \- .BR popen (3) for ivykis applications .SH SYNOPSIS .B #include .sp .nf struct iv_popen_request { char *file; char **argv; char *type; }; .fi .sp .BI "void IV_POPEN_REQUEST_INIT(struct iv_popen_request *" this ");" .br .BI "int iv_popen_request_submit(struct iv_popen_request *" this ");" .br .BI "void iv_popen_request_close(struct iv_popen_request *" this ");" .br .SH DESCRIPTION .B iv_popen provides .BR ivykis (3) applications with an asynchronous version of .BR popen (3) that is integrated with the ivykis event loop. .PP After initialising a .B struct iv_popen_request object using .B IV_POPEN_REQUEST_INIT and assigning its .B ->file and .B ->argv and .B ->type members, one can call .B iv_popen_request_submit on it to fork off a child process which will call .BR execvp(2) on .B ->file and .B ->argv, while in the parent process returning a file descriptor that is connected to the child's standard input (if .B ->type equals "w") or standard output (if .B ->type equals "r"). .PP When the application is done with the child process, it should call .B iv_popen_request_close, and close the file descriptor returned by .B iv_popen_request_submit (this is not done automatically). .PP .B iv_popen will continue to monitor the child's process state while it is running, by registering an .BR iv_wait (3) interest for its process ID. .PP If the child process has not yet terminated when .B iv_popen_request_close is called, .B iv_popen will attempt to terminate the child process in the background by sending it a series of SIGTERM and SIGKILL signals. .PP .B iv_popen_request_close must be called from the same thread that .B iv_popen_request_submit was called from on this object. .PP .PP .SH "SEE ALSO" .BR ivykis (3), .BR iv_wait (3), .BR execvp (2), .BR popen (3) ivykis-0.36.2/man3/iv_popen_request_close.3000066400000000000000000000000241210744026200206100ustar00rootroot00000000000000.so man3/iv_popen.3 ivykis-0.36.2/man3/iv_popen_request_submit.3000066400000000000000000000000241210744026200210060ustar00rootroot00000000000000.so man3/iv_popen.3 ivykis-0.36.2/man3/iv_quit.3000066400000000000000000000014231210744026200155200ustar00rootroot00000000000000.\" This man page is Copyright (C) 2003, 2010 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_quit 3 2010-08-15 "ivykis" "ivykis programmer's manual" .SH NAME iv_quit \- signal ivykis to exit the main loop .SH SYNOPSIS .B #include .sp .BI "void iv_quit(void);" .br .SH DESCRIPTION .B iv_quit signals ivykis to exit the current thread's main loop. .PP If called from any callback function, .B iv_quit will cause the .BR iv_main (3) function called from the current thread to return. It is not meant to be used casually. .SH "SEE ALSO" .BR ivykis (3), .BR iv_examples (3) ivykis-0.36.2/man3/iv_set_fatal_msg_handler.3000066400000000000000000000000241210744026200210370ustar00rootroot00000000000000.so man3/iv_fatal.3 ivykis-0.36.2/man3/iv_signal.3000066400000000000000000000057541210744026200160260ustar00rootroot00000000000000.\" This man page is Copyright (C) 2010 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_signal 3 2010-09-03 "ivykis" "ivykis programmer's manual" .SH NAME IV_SIGNAL_INIT, iv_signal_register, iv_signal_unregister \- ivykis signal handling .SH SYNOPSIS .B #include .sp .nf struct iv_signal { int signum; unsigned int flags; void *cookie; void (*handler)(void *); }; .fi .sp .BI "void IV_SIGNAL_INIT(struct iv_signal *" this ");" .br .BI "int iv_signal_register(struct iv_signal *" this ");" .br .BI "void iv_signal_unregister(struct iv_signal *" this ");" .br .SH DESCRIPTION .B iv_signal provides a way for .BR ivykis (3) applications to handle POSIX signals, by integrating them with the ivykis event loop. .PP An ivykis application desiring signal notification registers a .B struct iv_signal object by calling .B iv_signal_register, after having initialised it with .B IV_SIGNAL_INIT and subsequently having filled in the .B ->signum, .B ->cookie and .B ->handler members. .PP Once the signal indicated by .B ->signum is delivered to any thread in the current process, the callback specified by .B ->handler is scheduled to be called in the thread that the .B struct iv_signal object was registered in, with .B ->cookie as its sole argument. .PP If the same signal arrives again while the callback function is still running, the callback function is guaranteed to be called again after it returns. .PP It is permitted to register multiple .B struct iv_signal objects for the same signal number. If all such objects are registered with .B IV_SIGNAL_FLAG_EXCLUSIVE in .B ->flags unset, then all objects will have their callback functions called upon arrival of the signal, in no guaranteed order. .PP Invoking callback functions stops at the first .B struct iv_signal object with .B IV_SIGNAL_FLAG_EXCLUSIVE in .B ->flags set, so that if all objects have .B IV_SIGNAL_FLAG_EXCLUSIVE set, only one callback function will be invoked. .PP To deinitialize a .B struct iv_signal object, call .B iv_signal_unregister from the same thread that .B iv_signal_register was called from on that object. .PP It is permitted to unregister a .B struct iv_signal object from any ivykis callback function in the thread it was registered in, including from a callback function triggered by this object, and it is permitted to free the memory corresponding to an unregistered object from its own callback function. .PP It is guaranteed that signals delivered to child processes that were created by .BR fork (2) but that have not yet called .BR execve (2) will not cause .B iv_signal callbacks to be invoked in the parent process. .PP Internally, .B iv_signal is implemented using .BR iv_event_raw (3). .PP .SH "SEE ALSO" .BR ivykis (3), .BR iv_event_raw (3), .BR sigaction (2) ivykis-0.36.2/man3/iv_signal_register.3000066400000000000000000000000251210744026200177140ustar00rootroot00000000000000.so man3/iv_signal.3 ivykis-0.36.2/man3/iv_signal_unregister.3000066400000000000000000000000251210744026200202570ustar00rootroot00000000000000.so man3/iv_signal.3 ivykis-0.36.2/man3/iv_task.3000066400000000000000000000043561210744026200155100ustar00rootroot00000000000000.\" This man page is Copyright (C) 2003, 2010 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_task 3 2010-08-15 "ivykis" "ivykis programmer's manual" .SH NAME iv_task_register, iv_task_unregister, iv_task_registered \- deal with ivykis tasks .SH SYNOPSIS .B #include .sp .nf struct iv_task { void *cookie; void (*handler)(void *); }; .fi .sp .BI "void IV_TASK_INIT(struct iv_task *" task ");" .br .BI "void iv_task_register(struct iv_task *" task ");" .br .BI "void iv_task_unregister(struct iv_task *" task ");" .br .BI "int iv_task_registered(struct iv_task *" task ");" .br .SH DESCRIPTION The functions .B iv_task_register and .B iv_task_unregister register, respectively unregister, a task with the current thread's ivykis event loop. .B iv_task_registered on a task returns true if that task is currently registered with ivykis. .PP A task is like a timer, but with an immediate timeout. When a task is registered, unless it is unregistered again first, the callback function specified by .B ->handler is guaranteed to be called once, in the thread that the task was registered in, some time after control returns to the ivykis main loop but before ivykis will sleep for more events, with .B ->cookie as its first and sole argument. When this happens, the task is transparently unregistered. .PP Tasks are mainly used for scheduling code for execution where it is not appropriate to directly run that code in the calling context (for example, because the current context might be run as a callback function where the caller expects certain conditions to remain invariant after the callback completes). .PP The application is allowed to change the .B ->cookie and .B ->handler members at any time. .PP A given .B struct iv_task can only be registered in one thread at a time, and a task can only be unregistered in the thread that it was registered from. .PP There is no limit on the number of tasks registered at once. .PP See .BR iv_examples (3) for programming examples. .SH "SEE ALSO" .BR ivykis (3), .BR iv_examples (3) ivykis-0.36.2/man3/iv_task_register.3000066400000000000000000000000231210744026200173770ustar00rootroot00000000000000.so man3/iv_task.3 ivykis-0.36.2/man3/iv_task_registered.3000066400000000000000000000000231210744026200177100ustar00rootroot00000000000000.so man3/iv_task.3 ivykis-0.36.2/man3/iv_task_unregister.3000066400000000000000000000000231210744026200177420ustar00rootroot00000000000000.so man3/iv_task.3 ivykis-0.36.2/man3/iv_thread.3000066400000000000000000000036461210744026200160160ustar00rootroot00000000000000.\" This man page is Copyright (C) 2010 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_thread 3 2010-09-13 "ivykis" "ivykis programmer's manual" .SH NAME iv_thread_create, iv_thread_set_debug_state \- ivykis thread convenience functions .SH SYNOPSIS .B #include .sp .BI "int iv_thread_create(char *" name ", void (*" start_routine ")(void *), void *" arg ");" .br .BI "void iv_thread_set_debug_state(int " state ");" .br .SH DESCRIPTION .B iv_thread_create is a wrapper around .BR pthread_create (3) which will maintain an ivykis main loop reference in the calling thread (which must be an .BR ivykis (3) thread, i.e. have had .BR iv_init (3) called in it) for as long as the created thread is alive. .PP Maintaining a reference on the calling thread's ivykis event loop makes sure that the calling thread will not return from its ivykis main loop before the created thread exits, as that could cause cleanup still happening in the created thread to be interrupted when the calling thread subsequently calls .BR exit (3). .PP The created thread need not be an ivykis thread. .PP Enabling debugging by calling .B iv_thread_set_debug with a nonzero argument will print a debug message to standard error whenever a thread is created via .B iv_thread_create, whenever a thread so created terminates normally by returning from its .B start_routine, self-terminates by calling .BR pthread_exit (3), or is successfully canceled by .BR pthread_cancel (3), and whenever destruction of such a thread is signaled back to the calling thread. .PP For inter-thread signaling, .B iv_thread uses .BR iv_event (3). .PP .SH "SEE ALSO" .BR ivykis (3), .BR iv_event (3), .BR exit (3), .BR pthread_cancel (3), .BR pthread_create (3), .BR pthread_exit (3) ivykis-0.36.2/man3/iv_thread_create.3000066400000000000000000000000251210744026200173250ustar00rootroot00000000000000.so man3/iv_thread.3 ivykis-0.36.2/man3/iv_thread_set_debug_state.3000066400000000000000000000000251210744026200212230ustar00rootroot00000000000000.so man3/iv_thread.3 ivykis-0.36.2/man3/iv_time.3000066400000000000000000000023221210744026200154730ustar00rootroot00000000000000.\" This man page is Copyright (C) 2003 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_time 3 2003-03-29 "ivykis" "ivykis programmer's manual" .SH NAME iv_now, iv_validate_now, iv_invalidate_now \- ivykis time handling .SH SYNOPSIS .B #include .sp .BI "extern struct timespec " iv_now ";" .br .BI "void iv_validate_now(void);" .br .BI "void iv_invalidate_now(void);" .br .SH DESCRIPTION .B iv_now is a global variable that reflects the current time-of-day. Applications written to the ivykis API generally require to know the current time-of-day in many places, and therefore effort is done to cache this quantity. .PP The contents of .B iv_now might be stale. Calling the function .B iv_validate_now ensures that the current contents of .B iv_now are up-to-date. .PP The function .B iv_invalidate_now is called to invalidate the currently cached time-of-day. This function should be called after any operation that takes a significant amount of wall clock time. .SH "SEE ALSO" .BR ivykis (3), .BR iv_examples (3) ivykis-0.36.2/man3/iv_timer.3000066400000000000000000000040301210744026200156530ustar00rootroot00000000000000.\" This man page is Copyright (C) 2003, 2010 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_timer 3 2010-08-15 "ivykis" "ivykis programmer's manual" .SH NAME iv_timer_register, iv_timer_unregister, iv_timer_registered \- deal with ivykis timers .SH SYNOPSIS .B #include .sp .nf struct iv_timer { struct timespec expires; void *cookie; void (*handler)(void *); }; .fi .sp .BI "void IV_TIMER_INIT(struct iv_timer *" timer ");" .br .BI "void iv_timer_register(struct iv_timer *" timer ");" .br .BI "void iv_timer_unregister(struct iv_timer *" timer ");" .br .BI "int iv_timer_registered(struct iv_timer *" timer ");" .br .SH DESCRIPTION The functions .B iv_timer_register and .B iv_timer_unregister register, respectively unregister, a timer with the current thread's ivykis event loop. .B iv_timer_registered on a timer returns true if that timer is currently registered with ivykis. .PP When a timer that is registered becomes 'ready', due to the current system clock value becoming greater than or equal to the timer's .B ->expires member field, the callback function specified by .B ->handler is called in the thread that the timer was registered in, with .B ->cookie as its first and sole argument. When this happens, the timer is transparently unregistered. .PP The application is allowed to change the .B ->cookie and .B ->handler members at any time. The application is not allowed to change the .B ->expires member while the timer is registered. .PP A given .B struct iv_timer can only be registered in one thread at a time, and a timer can only be unregistered in the thread that it was registered from. .PP There is no limit on the number of timers registered at once. .PP See .BR iv_examples (3) for programming examples. .SH "SEE ALSO" .BR ivykis (3), .BR iv_examples (3) ivykis-0.36.2/man3/iv_timer_register.3000066400000000000000000000000241210744026200175560ustar00rootroot00000000000000.so man3/iv_timer.3 ivykis-0.36.2/man3/iv_timer_registered.3000066400000000000000000000000241210744026200200670ustar00rootroot00000000000000.so man3/iv_timer.3 ivykis-0.36.2/man3/iv_timer_unregister.3000066400000000000000000000000241210744026200201210ustar00rootroot00000000000000.so man3/iv_timer.3 ivykis-0.36.2/man3/iv_tls.3000066400000000000000000000057671210744026200153570ustar00rootroot00000000000000.\" This man page is Copyright (C) 2012 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_tls 3 2012-03-30 "ivykis" "ivykis programmer's manual" .SH NAME iv_tls_user_register, iv_tls_user_ptr \- thread-local storage handling for ivykis modules .SH SYNOPSIS .B #include .sp .nf struct iv_tls_user { size_t sizeof_state; void (*init_thread)(void *st); void (*deinit_thread)(void *st); }; .fi .sp .BI "void iv_tls_user_register(struct iv_tls_user *" tu ");" .br .BI "void *iv_tls_user_ptr(struct iv_tls_user *" tu ");" .br .SH DESCRIPTION The .B iv_tls interface provides thread-local storage handling to .B ivykis modules. .PP An ivykis module can arrange for an amount of memory to be allocated for its use in each ivykis thread by calling .B iv_tls_user_register. This must be done before any calls to .B iv_init have been made in this process, and is typically done from a module initialization function marked as a constructor function. .PP The .B ->sizeof_state member of the passed-in structure indicates how many bytes of memory the module wants allocated for its use in every ivykis thread. .PP When a thread calls .B iv_init, .B ->sizeof_state bytes of memory will be allocated for use by this module in that thread, and initialised to zero. A pointer to this memory area can be obtained by calling .B iv_tls_user_ptr (which returns NULL in non-ivykis threads). .PP If the specified .B ->init_thread function pointer is not NULL, it will be invoked at the end of .B iv_init, with its argument pointing to this thread's memory area allocation for this module. .PP If .B ->deinit_thread is not NULL, it will be invoked at the start of .B iv_deinit, or if the thread fails to call .B iv_deinit before terminating, at thread termination time. The argument passed into .B ->deinit_thread is the same as for .B ->init_thread. .PP It is permitted to call any ivykis API functions from the .B ->init_thread and .B ->deinit_thread callbacks. .PP There is no explicit serialization on calls to .B ->init_thread and .B ->deinit_thread. .PP Care must be taken when calling .B iv_tls_user_ptr from a signal handler, as there is a time window where it will return a non-NULL value before .B ->init_thread or after .B ->deinit_thread have been called. .PP Use of .B iv_tls for managing thread-local state is preferred over direct use of the .B __thread keyword, as not all platforms that ivykis runs on provide the .B __thread keyword. .PP Use of .B iv_tls for managing thread-local state is preferred over direct use of the .B pthread_key_create and .B pthread_setspecific APIs, as .B iv_tls provides a thread init hook as well as a destructor hook, and properly sequences .B ->init_thread and .B ->deinit_thread calls with core ivykis initialization and cleanup. .SH "SEE ALSO" .BR iv_init (3) ivykis-0.36.2/man3/iv_tls_user_ptr.3000066400000000000000000000000221210744026200172550ustar00rootroot00000000000000.so man3/iv_tls.3 ivykis-0.36.2/man3/iv_tls_user_register.3000066400000000000000000000000221210744026200202740ustar00rootroot00000000000000.so man3/iv_tls.3 ivykis-0.36.2/man3/iv_validate_now.3000066400000000000000000000000231210744026200172050ustar00rootroot00000000000000.so man3/iv_time.3 ivykis-0.36.2/man3/iv_wait.3000066400000000000000000000077321210744026200155130ustar00rootroot00000000000000.\" This man page is Copyright (C) 2010 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_wait 3 2010-09-03 "ivykis" "ivykis programmer's manual" .SH NAME IV_WAIT_INTEREST_INIT, iv_wait_interest_register, iv_wait_interest_register_spawn, iv_wait_interest_unregister, iv_wait_interest_kill \- ivykis .BR wait4 (2) wrapper .SH SYNOPSIS .B #include .sp .nf struct iv_wait_interest { pid_t pid; void *cookie; void (*handler)(void *cookie, int status, struct rusage *rusage); }; .fi .sp .BI "void IV_WAIT_INTEREST_INIT(struct iv_wait_interest *" this ");" .br .BI "int iv_wait_interest_register(struct iv_wait_interest *" this ");" .br .BI "int iv_wait_interest_register_spawn(struct iv_wait_interest *" this ", void (*" fn ")(void *), void *" cookie ");" .br .BI "void iv_wait_interest_unregister(struct iv_wait_interest *" this ");" .br .BI "int iv_wait_interest_kill(struct iv_wait_interest *" this ", int " sig ");" .br .SH DESCRIPTION .B iv_wait is an .BR ivykis (3) wrapper around .BR wait4 (2), integrating process state change notification with the ivykis event loop. .PP An ivykis application desiring process state change notifications registers a .B struct iv_wait_interest object by calling .B iv_wait_interest_register, after having initialised it with .B IV_WAIT_INTEREST_INIT and subsequently having filled in the .B ->pid, .B ->cookie and .B ->handler members. .PP Alternatively, an ivykis application can use .B iv_wait_interest_register_spawn to atomically fork off a child process and register a .B struct iv_wait_interest for it. In this context, 'atomically' means that the call to .B iv_wait_interest_register_spawn will be serialised with respect to invocations of .BR wait4 (2), which closes the race where process state change notifications can occur and be delivered between forking off the child process and registering a .B struct iv_wait_interest for the child's pid. The child process will run the function given by the .B iv_wait_interest_register_spawn argument .B fn, with argument .B cookie as its argument. .PP Once a process state change occurs (as indicated by delivery of a SIGCHLD signal to the current process), .B iv_wait calls .BR wait4 (2) to return information about the process state change, looks up the returned process ID in the set of registered .B struct iv_wait_interest objects, and if there is a registered interest with a matching .B ->pid field, arranges for that object's callback function to be called in the thread that the object was registered in. .PP Process state change notifications will continue to be delivered to the object's callback function until .B iv_wait_interest_unregister is called on the object or until a WIFEXITED or WIFSIGNALED status for this pid is returned by .BR wait4 (2). .PP Delivery of a WIFEXITED or WIFSIGNALED status does not automatically unregister the object, this always needs to be done explicitly. .PP Unregistering a .B struct iv_wait_interest object can only be done from the thread that that object was registered in, but within that thread, can safely be done from (and its underlying memory allocation can safely be freed from) its own callback function. .PP Registering multiple .B struct iv_wait_interest objects for the same process ID will produce undefined behavior. .PP To send a signal to a child process, use .B iv_wait_interest_kill. This function will internally serialise with invocations of .BR wait4(2), to avoid the race between sending a signal to a process and collecting a termination notification for that process (which makes its pid available for reuse). .PP Internally, .B iv_wait is implemented using .BR iv_signal (3) and .BR iv_event (3). .PP .SH "SEE ALSO" .BR ivykis (3), .BR iv_signal (3), .BR iv_event (3), .BR wait4 (2) ivykis-0.36.2/man3/iv_wait_interest_register.3000066400000000000000000000000231210744026200213160ustar00rootroot00000000000000.so man3/iv_wait.3 ivykis-0.36.2/man3/iv_wait_interest_register_spawn.3000066400000000000000000000000231210744026200225260ustar00rootroot00000000000000.so man3/iv_wait.3 ivykis-0.36.2/man3/iv_wait_interest_unregister.3000066400000000000000000000000231210744026200216610ustar00rootroot00000000000000.so man3/iv_wait.3 ivykis-0.36.2/man3/iv_work.3000066400000000000000000000105531210744026200155240ustar00rootroot00000000000000.\" This man page is Copyright (C) 2010 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH iv_work 3 2010-09-14 "ivykis" "ivykis programmer's manual" .SH NAME IV_WORK_POOL_INIT, iv_work_pool_create, iv_work_pool_put, IV_WORK_ITEM_INIT, iv_work_pool_submit_work \- ivykis worker thread management .SH SYNOPSIS .B #include .sp .nf struct iv_work_pool { int max_threads; void *cookie; void (*thread_start)(void *cookie); void (*thread_stop)(void *cookie); }; struct iv_work_item { void *cookie; void (*work)(void *cookie); void (*completion)(void *cookie); }; .fi .sp .BI "void IV_WORK_POOL_INIT(struct iv_work_pool *" this ");" .br .BI "int iv_work_pool_create(struct iv_work_pool *" this ");" .br .BI "int iv_work_pool_put(struct iv_work_pool *" this ");" .br .BI "void IV_WORK_ITEM_INIT(struct iv_work_item *" work ");" .br .BI "int iv_work_pool_submit_work(struct iv_work_pool *" this ", struct iv_work_item *" work ");" .br .SH DESCRIPTION Calling .B iv_work_pool_create on a .B struct iv_work_pool object previously initialised by .B IV_WORK_POOL_INIT creates a pool of worker threads that can be used to offload CPU intensive tasks to, so as to prevent negatively influencing event handling latency in the calling thread, and to enable the use of multiple host CPUs for CPU intensive tasks. .PP .B iv_work dynamically adjusts the number of threads in the pool to the amount of work there is to do. The .B ->max_threads member of .B struct iv_work_pool specifies the maximum number of threads that will be created in this pool. .PP Calling .B iv_work_pool_submit_work on a .B struct iv_work_item object previously initialised by .B IV_WORK_ITEM_INIT submits a work item to a pool. The .B ->work member of .B struct iv_work_item specifies the function that will be called in one of the worker threads in the pool specified by .B ->this, with .B ->cookie as its sole argument. When the work function has completed, .B iv_work will call the .B ->completion callback to indicate this, also with .B ->cookie as its sole argument, in the thread that .B iv_work_pool_create was called in for this pool object. .PP As a special case, calling .B iv_work_pool_submit_work with a .B NULL work pool pointer will cause the work item to be processed in the local thread, from an .BR iv_task (3) callback. .PP If the .B ->thread_start function pointer specified in .B struct iv_work_pool is not NULL, it will be called upon creation of a new worker thread, in the context of the created worker thread, with .B ->cookie as its sole argument. Calls to .B ->thread_start are not explicitly serialised, which should be kept in mind when manipulating state shared between threads from within that callback function. .PP Similarly, if .B iv_work decides to terminate a worker thread, for example due to inactivity, .B ->thread_stop will be called in the context of the terminating thread, with .B ->cookie as its sole argument. Calls to .B ->thread_stop are also not explicitly serialised. .PP .B iv_work_pool_submit_work can only be called from the thread that .B iv_work_pool_create for this pool object was called in. .PP There is no way to cancel submitted work items. .PP There is no guaranteed order, FIFO or otherwise, between different work items submitted to the same worker thread pool. .PP When the user has no more work items to submit to the pool, its reference to the pool can be dropped by calling .B iv_work_pool_put. .PP If there are still pending or running work items assigned to this pool when .B iv_work_pool_put is called, those work items will not be canceled, but will be allowed to run to completion, and their .B ->completion callbacks will be called as usual. A similar thing holds for the .B ->thread_start and .B ->thread_stop callbacks -- they can also still be called after .B iv_work_pool_put returns. Even so, the memory corresponding to the .B struct iv_work_pool can immediately be freed or reused by the user upon return of the .B iv_work_pool_put call. .PP Internally, .B iv_work uses .BR iv_thread (3) for its thread management. .PP .SH "SEE ALSO" .BR ivykis (3), .BR iv_thread (3) ivykis-0.36.2/man3/iv_work_pool_create.3000066400000000000000000000000231210744026200200670ustar00rootroot00000000000000.so man3/iv_work.3 ivykis-0.36.2/man3/iv_work_pool_put.3000066400000000000000000000000231210744026200174340ustar00rootroot00000000000000.so man3/iv_work.3 ivykis-0.36.2/man3/iv_work_pool_submit_work.3000066400000000000000000000000231210744026200211710ustar00rootroot00000000000000.so man3/iv_work.3 ivykis-0.36.2/man3/ivykis.3000066400000000000000000000055451210744026200153670ustar00rootroot00000000000000.\" This man page is Copyright (C) 2003, 2010 Lennert Buytenhek. .\" Permission is granted to distribute possibly modified copies .\" of this page provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .TH ivykis 3 2010-08-15 "ivykis" "ivykis programmer's manual" .SH NAME ivykis \- library for asynchronous I/O readiness notification .SH DESCRIPTION ivykis is a library for asynchronous I/O readiness notification. It is a thin, portable wrapper around OS-provided mechanisms such as .BR epoll_create (2), .BR kqueue (2), .BR poll (2), .BR poll (7d) (/dev/poll) and .BR port_create (3C). .PP ivykis was mainly designed for building high-performance network applications, but can be used in any event-driven application that uses .BR poll (2)able file descriptors as its event sources. .PP While some programming models dictate using blocking I/O and starting a thread per event source, programs written to the ivykis API are generally single-threaded (or use only a small number of threads), and never block on I/O. All input and output is done in a nonblocking fashion, with I/O readiness notifications delivered via callback functions. .PP The two main event sources in ivykis are file descriptors and timers. File descriptors generate an event when they become readable or writable or trigger an error condition, while timers generate an event when the system time increments past a certain pre-set time. Events associated with file descriptors are level-triggered -- a callback function set up to handle a certain file descriptor event will be called repeatedly until the condition generating the event has been cleared. .PP As mentioned, applications using ivykis are generally single-threaded. Event callbacks are strictly serialised within a thread, and non-preemptible. This mostly removes the need for locking of shared data, and generally simplifies writing applications. .PP Each thread that uses ivykis has its own file descriptors and timers, and runs a separate event loop. .PP In ivykis, all code that is not initialization code runs from callback functions. Callback functions are not allowed to block. If a particular piece of code wants to perform a certain operation that can block, it either has to schedule it to run in a separate thread, or it has to perform the operation in a nonblocking fashion instead. For example, registering an input callback function instead of blocking on a read, registering a timer instead of calling .BR sleep (2), etc. .PP In case of an internal error, ivykis will use .BR iv_fatal (3) to report the error. The application can provide a custom fatal error handler by calling .BR iv_set_fatal_msg_handler (3). .SH "SEE ALSO" .BR iv_examples (3), .BR iv_fatal (3), .BR iv_fd (3), .BR iv_timer (3), .BR iv_task (3), .BR iv_init (3), .BR iv_main (3), .BR iv_time (3) ivykis-0.36.2/misc/000077500000000000000000000000001210744026200140515ustar00rootroot00000000000000ivykis-0.36.2/misc/Makefile.am000066400000000000000000000001011210744026200160750ustar00rootroot00000000000000pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = ivykis.pc ivykis-0.36.2/misc/ivykis.pc.in000066400000000000000000000003401210744026200163150ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: ivykis Version: @VERSION@ Description: event handling library Cflags: -I${includedir} Libs: -L${libdir} -livykis Libs.private: @LIBS@ ivykis-0.36.2/src/000077500000000000000000000000001210744026200137055ustar00rootroot00000000000000ivykis-0.36.2/src/Makefile.am000066400000000000000000000034071210744026200157450ustar00rootroot00000000000000AM_CPPFLAGS = -D_GNU_SOURCE \ -I$(top_srcdir)/src/include \ -I$(top_builddir)/src/include lib_LTLIBRARIES = libivykis.la SRC = iv_avl.c \ iv_event.c \ iv_fatal.c \ iv_task.c \ iv_timer.c \ iv_tls.c \ iv_work.c INC = include/iv_avl.h \ include/iv_event.h \ include/iv_event_raw.h \ include/iv_list.h \ include/iv_thread.h \ include/iv_tls.h \ include/iv_work.h if HAVE_POSIX SRC += iv_event_raw_posix.c \ iv_fd.c \ iv_fd_poll.c \ iv_fd_pump.c \ iv_main_posix.c \ iv_popen.c \ iv_signal.c \ iv_thread_posix.c \ iv_time_posix.c \ iv_wait.c INC += include/iv_fd_pump.h \ include/iv_popen.h \ include/iv_signal.h \ include/iv_wait.h if HAVE_DEV_POLL SRC += iv_fd_dev_poll.c endif if HAVE_EPOLL SRC += iv_fd_epoll.c endif if HAVE_KQUEUE SRC += iv_fd_kqueue.c endif if HAVE_PORT SRC += iv_fd_port.c endif if HAVE_INOTIFY SRC += iv_inotify.c INC += include/iv_inotify.h endif LINKFLAGS = -version-info 3:5:3 if HAVE_VERSIONING LINKFLAGS += -Wl,--version-script,$(top_srcdir)/libivykis.posix.ver endif endif if HAVE_WIN32 SRC += iv_event_raw_win32.c \ iv_handle.c \ iv_main_win32.c \ iv_thread_win32.c \ iv_time_win32.c LINKFLAGS = -version-info 0:0:0 \ -Wl,--version-script,$(top_srcdir)/libivykis.win32.ver \ -no-undefined endif EXTRA_DIST = include/iv.h.in libivykis_la_SOURCES = $(SRC) libivykis_la_LDFLAGS = $(LINKFLAGS) include_HEADERS = $(INC) nodist_include_HEADERS = include/iv.h noinst_HEADERS = iv_event_private.h \ iv_fd_private.h \ iv_handle_private.h \ iv_private.h \ mutex.h \ spinlock.h ivykis-0.36.2/src/include/000077500000000000000000000000001210744026200153305ustar00rootroot00000000000000ivykis-0.36.2/src/include/iv.h.in000066400000000000000000000062041210744026200165260ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2009, 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __IV_H #define __IV_H #ifndef _WIN32 #include #include #include #include <@ac_cv_timespec_hdr@> #include #else #include #include #endif #ifdef __cplusplus extern "C" { #endif /* * Library initialisation, main loop. */ void iv_init(void); int iv_inited(void); void iv_main(void); void iv_quit(void); void iv_deinit(void); void iv_fatal(const char *fmt, ...) __attribute__((noreturn)) __attribute__((format(printf, 1, 2))); void iv_set_fatal_msg_handler(void (*handler)(const char *msg)); /* * Time handling. */ struct timespec *__iv_now_location(); void iv_validate_now(void); void iv_invalidate_now(void); #define iv_now (*__iv_now_location()) #ifndef _WIN32 /* * File descriptor handling. */ struct iv_fd { int fd; void *cookie; void (*handler_in)(void *); void (*handler_out)(void *); void (*handler_err)(void *); void *pad[11]; }; const char *iv_poll_method_name(void); void IV_FD_INIT(struct iv_fd *); void iv_fd_register(struct iv_fd *); int iv_fd_register_try(struct iv_fd *); void iv_fd_unregister(struct iv_fd *); int iv_fd_registered(struct iv_fd *); void iv_fd_set_handler_in(struct iv_fd *, void (*)(void *)); void iv_fd_set_handler_out(struct iv_fd *, void (*)(void *)); void iv_fd_set_handler_err(struct iv_fd *, void (*)(void *)); #endif #ifdef _WIN32 /* * Handle handling. */ struct iv_handle { HANDLE handle; void *cookie; void (*handler)(void *); void *pad[13]; }; void IV_HANDLE_INIT(struct iv_handle *); void iv_handle_register(struct iv_handle *); void iv_handle_unregister(struct iv_handle *); int iv_handle_registered(struct iv_handle *); void iv_handle_set_handler(struct iv_handle *, void (*)(void *)); #endif /* * Task handling. */ struct iv_task { void *cookie; void (*handler)(void *); void *pad[6]; }; void IV_TASK_INIT(struct iv_task *); void iv_task_register(struct iv_task *); void iv_task_unregister(struct iv_task *); int iv_task_registered(struct iv_task *); /* * Timer handling. */ struct iv_timer { struct timespec expires; void *cookie; void (*handler)(void *); void *pad[4]; }; void IV_TIMER_INIT(struct iv_timer *); void iv_timer_register(struct iv_timer *); void iv_timer_unregister(struct iv_timer *); int iv_timer_registered(struct iv_timer *); #ifdef __cplusplus } #endif #endif ivykis-0.36.2/src/include/iv_avl.h000066400000000000000000000051711210744026200167650ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __IV_AVL_H #define __IV_AVL_H #ifdef __cplusplus extern "C" { #endif #include struct iv_avl_node { struct iv_avl_node *left; struct iv_avl_node *right; struct iv_avl_node *parent; uint8_t height; }; struct iv_avl_tree { int (*compare)(struct iv_avl_node *a, struct iv_avl_node *b); struct iv_avl_node *root; }; #define IV_AVL_TREE_INIT(comp) \ { .compare = comp, .root = NULL } #define INIT_IV_AVL_TREE(tree, comp) \ do { \ (tree)->compare = (comp); \ (tree)->root = NULL; \ } while (0) int iv_avl_tree_insert(struct iv_avl_tree *tree, struct iv_avl_node *an); void iv_avl_tree_delete(struct iv_avl_tree *tree, struct iv_avl_node *an); struct iv_avl_node *iv_avl_tree_next(struct iv_avl_node *an); struct iv_avl_node *iv_avl_tree_prev(struct iv_avl_node *an); static inline int iv_avl_tree_empty(struct iv_avl_tree *tree) { return tree->root == NULL; } static inline struct iv_avl_node *iv_avl_tree_min(struct iv_avl_tree *tree) { if (tree->root != NULL) { struct iv_avl_node *an; an = tree->root; while (an->left != NULL) an = an->left; return an; } return NULL; } static inline struct iv_avl_node *iv_avl_tree_max(struct iv_avl_tree *tree) { if (tree->root != NULL) { struct iv_avl_node *an; an = tree->root; while (an->right != NULL) an = an->right; return an; } return NULL; } #define iv_avl_tree_for_each(an, tree) \ for (an = iv_avl_tree_min(tree); an != NULL; an = iv_avl_tree_next(an)) static inline struct iv_avl_node *iv_avl_tree_next_safe(struct iv_avl_node *an) { return an != NULL ? iv_avl_tree_next(an) : NULL; } #define iv_avl_tree_for_each_safe(an, an2, tree) \ for (an = iv_avl_tree_min(tree), an2 = iv_avl_tree_next_safe(an); \ an != NULL; an = an2, an2 = iv_avl_tree_next_safe(an)) #ifdef __cplusplus } #endif #endif ivykis-0.36.2/src/include/iv_event.h000066400000000000000000000024161210744026200173230ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __IV_EVENT_H #define __IV_EVENT_H #include #include #ifdef __cplusplus extern "C" { #endif struct iv_event { void *cookie; void (*handler)(void *); void *tinfo; struct iv_list_head list; }; static inline void IV_EVENT_INIT(struct iv_event *this) { } int iv_event_register(struct iv_event *this); void iv_event_unregister(struct iv_event *this); void iv_event_post(struct iv_event *this); #ifdef __cplusplus } #endif #endif ivykis-0.36.2/src/include/iv_event_raw.h000066400000000000000000000025351210744026200201760ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010, 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __IV_EVENT_RAW_H #define __IV_EVENT_RAW_H #include #ifdef __cplusplus extern "C" { #endif struct iv_event_raw { void *cookie; void (*handler)(void *); #ifndef _WIN32 struct iv_fd event_rfd; int event_wfd; #else struct iv_handle h; #endif }; static inline void IV_EVENT_RAW_INIT(struct iv_event_raw *this) { } int iv_event_raw_register(struct iv_event_raw *this); void iv_event_raw_unregister(struct iv_event_raw *this); void iv_event_raw_post(struct iv_event_raw *this); #ifdef __cplusplus } #endif #endif ivykis-0.36.2/src/include/iv_fd_pump.h000066400000000000000000000026371210744026200176410ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2011 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __IV_FD_PUMP_H #define __IV_FD_PUMP_H #ifdef __cplusplus extern "C" { #endif struct iv_fd_pump { int from_fd; int to_fd; void *cookie; void (*set_bands)(void *cookie, int pollin, int pollout); unsigned int flags; void *buf; int bytes; int full; int saw_fin; }; static inline void IV_FD_PUMP_INIT(struct iv_fd_pump *this) { } #define IV_FD_PUMP_FLAG_RELAY_EOF 1 void iv_fd_pump_init(struct iv_fd_pump *ip); void iv_fd_pump_destroy(struct iv_fd_pump *ip); int iv_fd_pump_pump(struct iv_fd_pump *ip); int iv_fd_pump_is_done(struct iv_fd_pump *ip); #ifdef __cplusplus } #endif #endif ivykis-0.36.2/src/include/iv_inotify.h000066400000000000000000000032621210744026200176630ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2008, 2009 Ronald Huizer * Dedicated to Kanna Ishihara. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __IV_INOTIFY_H #define __IV_INOTIFY_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif struct iv_inotify { /* No public members. */ struct iv_fd fd; struct iv_avl_tree watches; void **term; }; static inline void IV_INOTIFY_INIT(struct iv_inotify *this) { } int iv_inotify_register(struct iv_inotify *); void iv_inotify_unregister(struct iv_inotify *); struct iv_inotify_watch { struct iv_inotify *inotify; const char *pathname; uint32_t mask; void *cookie; void (*handler)(void *, struct inotify_event *); int wd; struct iv_avl_node an; }; static inline void IV_INOTIFY_WATCH_INIT(struct iv_inotify_watch *this) { } int iv_inotify_watch_register(struct iv_inotify_watch *); void iv_inotify_watch_unregister(struct iv_inotify_watch *); #ifdef __cplusplus } #endif #endif ivykis-0.36.2/src/include/iv_list.h000066400000000000000000000070641210744026200171610ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ /* * This file contains a doubly linked list implementation API-compatible * with the one found in the Linux kernel (in include/linux/list.h). */ #ifndef __IV_LIST_H #define __IV_LIST_H #include #ifdef __cplusplus extern "C" { #endif struct iv_list_head { struct iv_list_head *next; struct iv_list_head *prev; }; #define IV_LIST_HEAD_INIT(name) { &(name), &(name) } #define INIT_IV_LIST_HEAD(ilh) do { \ (ilh)->next = (ilh); \ (ilh)->prev = (ilh); \ } while (0) static inline void iv_list_add(struct iv_list_head *ilh, struct iv_list_head *head) { ilh->next = head->next; ilh->prev = head; head->next->prev = ilh; head->next = ilh; } static inline void iv_list_add_tail(struct iv_list_head *ilh, struct iv_list_head *head) { ilh->next = head; ilh->prev = head->prev; head->prev->next = ilh; head->prev = ilh; } static inline void iv_list_del(struct iv_list_head *ilh) { ilh->prev->next = ilh->next; ilh->next->prev = ilh->prev; ilh->prev = NULL; ilh->next = NULL; } static inline void iv_list_del_init(struct iv_list_head *ilh) { ilh->prev->next = ilh->next; ilh->next->prev = ilh->prev; INIT_IV_LIST_HEAD(ilh); } static inline int iv_list_empty(struct iv_list_head *head) { return head->next == head; } static inline void __iv_list_splice(struct iv_list_head *ilh, struct iv_list_head *prev, struct iv_list_head *next) { struct iv_list_head *first = ilh->next; struct iv_list_head *last = ilh->prev; first->prev = prev; prev->next = first; last->next = next; next->prev = last; } static inline void iv_list_splice(struct iv_list_head *ilh, struct iv_list_head *head) { if (!iv_list_empty(ilh)) __iv_list_splice(ilh, head, head->next); } static inline void iv_list_splice_init(struct iv_list_head *ilh, struct iv_list_head *head) { if (!iv_list_empty(ilh)) { __iv_list_splice(ilh, head, head->next); INIT_IV_LIST_HEAD(ilh); } } static inline void iv_list_splice_tail(struct iv_list_head *ilh, struct iv_list_head *head) { if (!iv_list_empty(ilh)) __iv_list_splice(ilh, head->prev, head); } static inline void iv_list_splice_tail_init(struct iv_list_head *ilh, struct iv_list_head *head) { if (!iv_list_empty(ilh)) { __iv_list_splice(ilh, head->prev, head); INIT_IV_LIST_HEAD(ilh); } } #define iv_container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member) *__ptr = (ptr); \ (type *)((char *)__ptr - (intptr_t)(&((type *)0)->member)); }) #define iv_list_entry(ilh, type, member) \ iv_container_of(ilh, type, member) #define iv_list_for_each(ilh, head) \ for (ilh = (head)->next; ilh != (head); ilh = ilh->next) #define iv_list_for_each_safe(ilh, ilh2, head) \ for (ilh = (head)->next, ilh2 = ilh->next; ilh != (head); \ ilh = ilh2, ilh2 = ilh->next) #ifdef __cplusplus } #endif #endif ivykis-0.36.2/src/include/iv_popen.h000066400000000000000000000023201210744026200173150ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __IV_POPEN_H #define __IV_POPEN_H #ifdef __cplusplus extern "C" { #endif struct iv_popen_request { char *file; char **argv; char *type; void *child; }; static inline void IV_POPEN_REQUEST_INIT(struct iv_popen_request *this) { } int iv_popen_request_submit(struct iv_popen_request *this); void iv_popen_request_close(struct iv_popen_request *this); #ifdef __cplusplus } #endif #endif ivykis-0.36.2/src/include/iv_signal.h000066400000000000000000000025731210744026200174630ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __IV_SIGNAL_H #define __IV_SIGNAL_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif struct iv_signal { int signum; unsigned int flags; void *cookie; void (*handler)(void *); struct iv_avl_node an; uint8_t active; struct iv_event_raw ev; }; static inline void IV_SIGNAL_INIT(struct iv_signal *this) { } #define IV_SIGNAL_FLAG_EXCLUSIVE 1 int iv_signal_register(struct iv_signal *this); void iv_signal_unregister(struct iv_signal *this); #ifdef __cplusplus } #endif #endif ivykis-0.36.2/src/include/iv_thread.h000066400000000000000000000021651210744026200174520ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __IV_THREAD_H #define __IV_THREAD_H #ifdef __cplusplus extern "C" { #endif int iv_thread_create(char *name, void (*start_routine)(void *), void *arg); void iv_thread_set_debug_state(int state); unsigned long iv_thread_get_id(void); void iv_thread_list_children(void); #ifdef __cplusplus } #endif #endif ivykis-0.36.2/src/include/iv_tls.h000066400000000000000000000023071210744026200170030ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2011 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __IV_TLS_H #define __IV_TLS_H #include #ifdef __cplusplus extern "C" { #endif struct iv_tls_user { size_t sizeof_state; void (*init_thread)(void *st); void (*deinit_thread)(void *st); struct iv_list_head list; int state_offset; }; void iv_tls_user_register(struct iv_tls_user *); void *iv_tls_user_ptr(struct iv_tls_user *); #ifdef __cplusplus } #endif #endif ivykis-0.36.2/src/include/iv_wait.h000066400000000000000000000032441210744026200171460ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __IV_WAIT_H #define __IV_WAIT_H #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif struct iv_wait_interest { pid_t pid; void *cookie; void (*handler)(void *cookie, int status, struct rusage *rusage); struct iv_avl_node avl_node; struct iv_event ev; struct iv_list_head events; void *dummy; unsigned int flags; }; static inline void IV_WAIT_INTEREST_INIT(struct iv_wait_interest *this) { } void iv_wait_interest_register(struct iv_wait_interest *this); int iv_wait_interest_register_spawn(struct iv_wait_interest *this, void (*fn)(void *cookie), void *cookie); void iv_wait_interest_unregister(struct iv_wait_interest *this); int iv_wait_interest_kill(struct iv_wait_interest *this, int sig); #ifdef __cplusplus } #endif #endif ivykis-0.36.2/src/include/iv_work.h000066400000000000000000000031751210744026200171670ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __IV_WORK_H #define __IV_WORK_H #include #include #ifdef __cplusplus extern "C" { #endif struct iv_work_pool { int max_threads; void *cookie; void (*thread_start)(void *cookie); void (*thread_stop)(void *cookie); void *priv; }; struct iv_work_item { void *cookie; void (*work)(void *cookie); void (*completion)(void *cookie); struct iv_list_head list; }; static inline void IV_WORK_POOL_INIT(struct iv_work_pool *this) { this->thread_start = NULL; this->thread_stop = NULL; } static inline void IV_WORK_ITEM_INIT(struct iv_work_item *this) { } int iv_work_pool_create(struct iv_work_pool *this); void iv_work_pool_put(struct iv_work_pool *this); void iv_work_pool_submit_work(struct iv_work_pool *this, struct iv_work_item *work); #ifdef __cplusplus } #endif #endif ivykis-0.36.2/src/iv_avl.c000066400000000000000000000227031210744026200153350ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include "iv_avl.h" static int height(struct iv_avl_node *an) { return an != NULL ? an->height : 0; } static void recalc_height(struct iv_avl_node *an) { int hl; int hr; hl = height(an->left); hr = height(an->right); an->height = 1 + ((hl > hr) ? hl : hr); } /* * There are four different rotations that may need to be performed * to rebalance subtrees after an insertion or deletion operation. * * In the diagrams below, the letters a - g symbolise tree nodes or * subtrees, where capital letters denote nodes that are guaranteed * to be present, and lower case letters denote nodes that may be NULL. * * The tables document the balance factors for each of the capital * letter nodes, where the balance factor is defined as the height of * the right subtree minus the height of the left subtree. * * * left rotation: * * B D before | after * / \ / \ B D | D B * a D => B E --------+-------- * / \ / \ +2 0 | -1 +1 * c E a c +2 +1 | 0 0 * * * right rotation: * * D B before | after * / \ / \ D B | B D * B e => A D --------+-------- * / \ / \ -2 -1 | 0 0 * A c c e -2 0 | +1 -1 * * * left-right rotation: * * F D before | after * / \ / \ F B D | D B F * B g => / \ ------------+------------ * / \ B F -2 +1 -1 | 0 0 +1 * a D / \ / \ -2 +1 0 | 0 0 0 * / \ a c e g -2 +1 +1 | 0 -1 0 * c e * * * right-left rotation: * * B D before | after * / \ / \ B F D | D B F * a F => / \ ------------+------------ * / \ B F +2 -1 -1 | 0 0 +1 * D g / \ / \ +2 -1 0 | 0 0 0 * / \ a c e g +2 -1 +1 | 0 -1 0 * c e */ static void rotate_left(struct iv_avl_node **root) { struct iv_avl_node *b = *root; struct iv_avl_node *d = b->right; struct iv_avl_node *c; c = d->left; b->right = c; if (c != NULL) c->parent = b; recalc_height(b); d->left = b; d->parent = b->parent; b->parent = d; recalc_height(d); *root = d; } static void rotate_right(struct iv_avl_node **root) { struct iv_avl_node *d = *root; struct iv_avl_node *b = d->left; struct iv_avl_node *c; c = b->right; d->left = c; if (c != NULL) c->parent = d; recalc_height(d); b->right = d; b->parent = d->parent; d->parent = b; recalc_height(b); *root = b; } static void rotate_left_right(struct iv_avl_node **root) { struct iv_avl_node *f = *root; struct iv_avl_node *b = f->left; struct iv_avl_node *d = b->right; struct iv_avl_node *c; struct iv_avl_node *e; c = d->left; b->right = c; if (c != NULL) c->parent = b; recalc_height(b); e = d->right; f->left = e; if (e != NULL) e->parent = f; recalc_height(f); d->left = b; d->right = f; d->parent = f->parent; b->parent = d; f->parent = d; recalc_height(d); *root = d; } static void rotate_right_left(struct iv_avl_node **root) { struct iv_avl_node *b = *root; struct iv_avl_node *f = b->right; struct iv_avl_node *d = f->left; struct iv_avl_node *c; struct iv_avl_node *e; c = d->left; b->right = c; if (c != NULL) c->parent = b; recalc_height(b); e = d->right; f->left = e; if (e != NULL) e->parent = f; recalc_height(f); d->left = b; d->right = f; d->parent = b->parent; b->parent = d; f->parent = d; recalc_height(d); *root = d; } static int balance(struct iv_avl_node *an) { return height(an->right) - height(an->left); } static void rebalance_node(struct iv_avl_node **_root) { struct iv_avl_node *root = *_root; int bal; bal = balance(root); if (bal == -2) { if (balance(root->left) <= 0) rotate_right(_root); else rotate_left_right(_root); } else if (bal == 2) { if (balance(root->right) < 0) rotate_right_left(_root); else rotate_left(_root); } } /* * Find the address of the (child) pointer that points to an. */ static struct iv_avl_node ** find_reference(struct iv_avl_tree *tree, struct iv_avl_node *an) { if (an->parent != NULL) { if (an->parent->left == an) return &an->parent->left; else return &an->parent->right; } else { return &tree->root; } } static void replace_reference(struct iv_avl_tree *tree, struct iv_avl_node *an, struct iv_avl_node *new_child) { *find_reference(tree, an) = new_child; } /* * Rebalance the tree from an back to the root. Rebalancing can stop * at the first node where no re-balancing was needed, or where * re-balancing restored the height of the subtree to what it was * before the insertion or deletion. */ static void rebalance_path(struct iv_avl_tree *tree, struct iv_avl_node *an) { while (an != NULL) { int old_height; struct iv_avl_node **ref; old_height = an->height; recalc_height(an); ref = find_reference(tree, an); rebalance_node(ref); an = *ref; if (old_height == an->height) break; an = an->parent; } } int iv_avl_tree_insert(struct iv_avl_tree *tree, struct iv_avl_node *an) { struct iv_avl_node *p; struct iv_avl_node **pp; /* * Find the node to which an is to be attached as a leaf. */ p = NULL; pp = &tree->root; while (*pp != NULL) { int ret; p = *pp; ret = tree->compare(an, p); if (ret < 0) pp = &p->left; else if (ret > 0) pp = &p->right; else return -1; } /* * Insert an. */ an->left = NULL; an->right = NULL; an->parent = p; an->height = 1; *pp = an; /* * Start rebalancing from an's parent. */ rebalance_path(tree, p); return 0; } static struct iv_avl_node * iv_avl_tree_delete_leaf(struct iv_avl_tree *tree, struct iv_avl_node *an) { /* * Simply replace the reference from an's parent to an by NULL, * and start rebalancing from an's parent. */ replace_reference(tree, an, NULL); return an->parent; } static struct iv_avl_node * iv_avl_tree_delete_nonleaf(struct iv_avl_tree *tree, struct iv_avl_node *an) { struct iv_avl_node *victim; struct iv_avl_node *p; /* * an is not a leaf node, so removing it is slightly more * complicated than NULLing its parent's reference to it. * * an will be replaced by either the maximum node in the * left subtree or the minimum node in the right subtree, * depending on the relative heights of those subtrees. We * call the replacing node the victim node. * * The victim node, i.e. the maximum (minimum) node in the * left (right) subtree could still have a left (right) child * node. Here, we replace the victim node by its child, and * unlink the victim node from the tree. */ if (height(an->left) > height(an->right)) { victim = an->left; while (victim->right != NULL) victim = victim->right; replace_reference(tree, victim, victim->left); if (victim->left != NULL) victim->left->parent = victim->parent; } else { victim = an->right; while (victim->left != NULL) victim = victim->left; replace_reference(tree, victim, victim->right); if (victim->right != NULL) victim->right->parent = victim->parent; } /* * We will start rebalancing the tree from the victim node's * original parent, unless that original parent is an, in which * case we will start rebalancing from the victim node itself * (after it has replaced an). */ p = victim->parent; if (p == an) p = victim; /* * Point an's parent's pointer to it to victim, move an's * children to victim, and make an's children point back to * victim as their parent. */ replace_reference(tree, an, victim); victim->left = an->left; victim->right = an->right; victim->parent = an->parent; victim->height = an->height; if (victim->left != NULL) victim->left->parent = victim; if (victim->right != NULL) victim->right->parent = victim; return p; } void iv_avl_tree_delete(struct iv_avl_tree *tree, struct iv_avl_node *an) { struct iv_avl_node *p; if (an->left == NULL && an->right == NULL) p = iv_avl_tree_delete_leaf(tree, an); else p = iv_avl_tree_delete_nonleaf(tree, an); rebalance_path(tree, p); } struct iv_avl_node *iv_avl_tree_next(struct iv_avl_node *an) { struct iv_avl_node *p; if (an->right != NULL) { an = an->right; while (an->left != NULL) an = an->left; return an; } p = an->parent; while (p != NULL && an == p->right) { an = p; p = an->parent; } return p; } struct iv_avl_node *iv_avl_tree_prev(struct iv_avl_node *an) { struct iv_avl_node *p; if (an->left != NULL) { an = an->left; while (an->right != NULL) an = an->right; return an; } p = an->parent; while (p != NULL && an == p->left) { an = p; p = an->parent; } return p; } ivykis-0.36.2/src/iv_event.c000066400000000000000000000100371210744026200156710ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010, 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "iv_private.h" #include "iv_event_private.h" #include "mutex.h" struct iv_event_thr_info { int event_count; union { struct iv_event_raw ier; struct iv_state *st; } u; __mutex_t list_mutex; struct iv_list_head pending_events; }; static int iv_event_use_event_raw; static void __iv_event_run_pending_events(void *_tinfo) { struct iv_event_thr_info *tinfo = _tinfo; struct iv_list_head events; mutex_lock(&tinfo->list_mutex); __iv_list_steal_elements(&tinfo->pending_events, &events); while (!iv_list_empty(&events)) { struct iv_event *ie; ie = iv_container_of(events.next, struct iv_event, list); iv_list_del_init(&ie->list); mutex_unlock(&tinfo->list_mutex); ie->handler(ie->cookie); mutex_lock(&tinfo->list_mutex); } mutex_unlock(&tinfo->list_mutex); } static void iv_event_tls_init_thread(void *_tinfo) { struct iv_event_thr_info *tinfo = _tinfo; tinfo->event_count = 0; IV_EVENT_RAW_INIT(&tinfo->u.ier); tinfo->u.ier.cookie = tinfo; tinfo->u.ier.handler = __iv_event_run_pending_events; mutex_init(&tinfo->list_mutex); INIT_IV_LIST_HEAD(&tinfo->pending_events); } static void iv_event_tls_deinit_thread(void *_tinfo) { struct iv_event_thr_info *tinfo = _tinfo; mutex_destroy(&tinfo->list_mutex); } static struct iv_tls_user iv_event_tls_user = { .sizeof_state = sizeof(struct iv_event_thr_info), .init_thread = iv_event_tls_init_thread, .deinit_thread = iv_event_tls_deinit_thread, }; static void iv_event_tls_init(void) __attribute__((constructor)); static void iv_event_tls_init(void) { iv_tls_user_register(&iv_event_tls_user); } void iv_event_run_pending_events(void) { __iv_event_run_pending_events(iv_tls_user_ptr(&iv_event_tls_user)); } int iv_event_register(struct iv_event *this) { struct iv_event_thr_info *tinfo = iv_tls_user_ptr(&iv_event_tls_user); if (!tinfo->event_count++) { if (!iv_event_use_event_raw) { struct iv_state *st = iv_get_state(); if (event_rx_on(st) == 0) tinfo->u.st = st; else iv_event_use_event_raw = 1; } if (iv_event_use_event_raw) { int ret; ret = iv_event_raw_register(&tinfo->u.ier); if (ret) { tinfo->event_count--; return ret; } } } this->tinfo = tinfo; INIT_IV_LIST_HEAD(&this->list); return 0; } void iv_event_unregister(struct iv_event *this) { struct iv_event_thr_info *tinfo = iv_tls_user_ptr(&iv_event_tls_user); if (!iv_list_empty(&this->list)) { mutex_lock(&tinfo->list_mutex); iv_list_del(&this->list); mutex_unlock(&tinfo->list_mutex); } if (!--tinfo->event_count) { if (!iv_event_use_event_raw) { event_rx_off(tinfo->u.st); tinfo->u.st = NULL; } else { iv_event_raw_unregister(&tinfo->u.ier); } } } void iv_event_post(struct iv_event *this) { struct iv_event_thr_info *tinfo = this->tinfo; int post; post = 0; mutex_lock(&tinfo->list_mutex); if (iv_list_empty(&this->list)) { if (iv_list_empty(&tinfo->pending_events)) post = 1; iv_list_add_tail(&this->list, &tinfo->pending_events); } mutex_unlock(&tinfo->list_mutex); if (post) { if (!iv_event_use_event_raw) event_send(tinfo->u.st); else iv_event_raw_post(&tinfo->u.ier); } } ivykis-0.36.2/src/iv_event_private.h000066400000000000000000000025321210744026200174310ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _WIN32 #include "iv_fd_private.h" static inline int event_rx_on(struct iv_state *st) { if (method->event_rx_on != NULL) return method->event_rx_on(st); return -1; } static inline void event_rx_off(struct iv_state *st) { method->event_rx_off(st); } static inline void event_send(struct iv_state *dest) { method->event_send(dest); } #else static inline int event_rx_on(struct iv_state *st) { return -1; } static inline void event_rx_off(struct iv_state *st) { } static inline void event_send(struct iv_state *dest) { } #endif ivykis-0.36.2/src/iv_event_raw_posix.c000066400000000000000000000063671210744026200177770ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include "config.h" #include "iv_private.h" #include "iv_fd_private.h" /* eventfd syscall **********************************************************/ #ifdef HAVE_SYS_EVENTFD_H #include #endif #if defined(HAVE_EVENTFD) && defined(EFD_NONBLOCK) && defined(EFD_CLOEXEC) static int grab_eventfd(void) { int fd; fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); if (fd < 0) { if (errno != EINVAL && errno != ENOSYS) perror("eventfd"); return -errno; } return fd; } #else static int grab_eventfd(void) { return -ENOSYS; } #endif /* implementation ***********************************************************/ static int eventfd_unavailable; static void iv_event_raw_got_event(void *_this) { struct iv_event_raw *this = (struct iv_event_raw *)_this; int toread; char buf[1024]; int ret; toread = eventfd_unavailable ? sizeof(buf) : 8; do { ret = read(this->event_rfd.fd, buf, toread); } while (ret < 0 && errno == EINTR); if (ret <= 0) { if (ret == 0) { iv_fatal("iv_event_raw: reading from event fd " "returned zero"); } else if (errno != EAGAIN) { iv_fatal("iv_event_raw: reading from event fd " "returned error %d[%s]", errno, strerror(errno)); } return; } this->handler(this->cookie); } int iv_event_raw_register(struct iv_event_raw *this) { int fd[2]; if (!eventfd_unavailable) { int ret; ret = grab_eventfd(); if (ret < 0) { if (ret != -EINVAL && ret != -ENOSYS) return -1; eventfd_unavailable = 1; } else { fd[0] = ret; fd[1] = ret; } } if (eventfd_unavailable) { if (pipe(fd) < 0) { perror("pipe"); return -1; } } IV_FD_INIT(&this->event_rfd); this->event_rfd.fd = fd[0]; this->event_rfd.cookie = this; this->event_rfd.handler_in = iv_event_raw_got_event; iv_fd_register(&this->event_rfd); this->event_wfd = fd[1]; if (eventfd_unavailable) { iv_fd_set_cloexec(fd[1]); iv_fd_set_nonblock(fd[1]); } return 0; } void iv_event_raw_unregister(struct iv_event_raw *this) { iv_fd_unregister(&this->event_rfd); close(this->event_rfd.fd); if (eventfd_unavailable) close(this->event_wfd); } void iv_event_raw_post(struct iv_event_raw *this) { if (eventfd_unavailable) { write(this->event_wfd, "", 1); } else { uint64_t x = 1; write(this->event_wfd, &x, sizeof(x)); } } ivykis-0.36.2/src/iv_event_raw_win32.c000066400000000000000000000026551210744026200175730ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include "config.h" int iv_event_raw_register(struct iv_event_raw *this) { HANDLE h; h = CreateEvent(NULL, FALSE, FALSE, NULL); if (h == NULL) return -1; IV_HANDLE_INIT(&this->h); this->h.handle = h; this->h.cookie = this->cookie; this->h.handler = this->handler; iv_handle_register(&this->h); return 0; } void iv_event_raw_unregister(struct iv_event_raw *this) { iv_handle_unregister(&this->h); CloseHandle(this->h.handle); } void iv_event_raw_post(struct iv_event_raw *this) { SetEvent(this->h.handle); } ivykis-0.36.2/src/iv_fatal.c000066400000000000000000000030071210744026200156360ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #ifndef _WIN32 #include static void iv_fatal_default_handler(const char *msg) { syslog(LOG_CRIT, "%s", msg); } #else static void iv_fatal_default_handler(const char *msg) { fprintf(stderr, "%s\n", msg); } #endif static void (*fatal_msg_handler)(const char *msg); void iv_fatal(const char *fmt, ...) { va_list ap; char msg[1024]; va_start(ap, fmt); vsnprintf(msg, sizeof(msg), fmt, ap); va_end(ap); msg[sizeof(msg) - 1] = 0; if (fatal_msg_handler != NULL) fatal_msg_handler(msg); else iv_fatal_default_handler(msg); abort(); } void iv_set_fatal_msg_handler(void (*handler)(const char *msg)) { fatal_msg_handler = handler; } ivykis-0.36.2/src/iv_fd.c000066400000000000000000000210071210744026200151400ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2009, 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "iv_private.h" #include "iv_fd_private.h" /* internal use *************************************************************/ int maxfd; struct iv_fd_poll_method *method; static void sanitise_nofile_rlimit(int euid) { struct rlimit lim; getrlimit(RLIMIT_NOFILE, &lim); maxfd = lim.rlim_cur; if (euid) { if (lim.rlim_cur < lim.rlim_max) { lim.rlim_cur = (unsigned int)lim.rlim_max & 0x7FFFFFFF; if (lim.rlim_cur > 131072) lim.rlim_cur = 131072; if (setrlimit(RLIMIT_NOFILE, &lim) >= 0) maxfd = lim.rlim_cur; } } else { lim.rlim_cur = 131072; lim.rlim_max = 131072; while (lim.rlim_cur > maxfd) { if (setrlimit(RLIMIT_NOFILE, &lim) >= 0) { maxfd = lim.rlim_cur; break; } lim.rlim_cur /= 2; lim.rlim_max /= 2; } } } static int method_is_excluded(char *exclude, char *name) { if (exclude != NULL) { char method_name[64]; int len; while (sscanf(exclude, "%63s%n", method_name, &len) > 0) { if (!strcmp(name, method_name)) return 1; exclude += len; } } return 0; } static void consider_poll_method(struct iv_state *st, char *exclude, struct iv_fd_poll_method *m) { if (method == NULL && !method_is_excluded(exclude, m->name)) { if (m->init(st) >= 0) method = m; } } static void iv_fd_init_first_thread(struct iv_state *st) { int euid; char *exclude; euid = geteuid(); signal(SIGPIPE, SIG_IGN); signal(SIGURG, SIG_IGN); sanitise_nofile_rlimit(euid); exclude = getenv("IV_EXCLUDE_POLL_METHOD"); if (exclude != NULL && getuid() != euid) exclude = NULL; #ifdef HAVE_PORT_CREATE consider_poll_method(st, exclude, &iv_fd_poll_method_port); #endif #ifdef HAVE_SYS_DEVPOLL_H consider_poll_method(st, exclude, &iv_fd_poll_method_dev_poll); #endif #ifdef HAVE_EPOLL_CREATE consider_poll_method(st, exclude, &iv_fd_poll_method_epoll); #endif #ifdef HAVE_KQUEUE consider_poll_method(st, exclude, &iv_fd_poll_method_kqueue); #endif consider_poll_method(st, exclude, &iv_fd_poll_method_poll); if (method == NULL) iv_fatal("iv_init: can't find suitable event dispatcher"); } void iv_fd_init(struct iv_state *st) { if (method == NULL) iv_fd_init_first_thread(st); else if (method->init(st) < 0) iv_fatal("iv_init: can't initialize event dispatcher"); st->numfds = 0; st->handled_fd = NULL; } void iv_fd_deinit(struct iv_state *st) { method->deinit(st); } void iv_fd_poll_and_run(struct iv_state *st, struct timespec *to) { struct iv_list_head active; __iv_invalidate_now(st); INIT_IV_LIST_HEAD(&active); method->poll(st, &active, to); while (!iv_list_empty(&active)) { struct iv_fd_ *fd; fd = iv_list_entry(active.next, struct iv_fd_, list_active); iv_list_del_init(&fd->list_active); st->handled_fd = fd; if (fd->ready_bands & MASKERR) if (fd->handler_err != NULL) fd->handler_err(fd->cookie); if (st->handled_fd != NULL && fd->ready_bands & MASKIN) if (fd->handler_in != NULL) fd->handler_in(fd->cookie); if (st->handled_fd != NULL && fd->ready_bands & MASKOUT) if (fd->handler_out != NULL) fd->handler_out(fd->cookie); } } void iv_fd_make_ready(struct iv_list_head *active, struct iv_fd_ *fd, int bands) { if (iv_list_empty(&fd->list_active)) { fd->ready_bands = 0; iv_list_add_tail(&fd->list_active, active); } fd->ready_bands |= bands; } void iv_fd_set_cloexec(int fd) { int flags; flags = fcntl(fd, F_GETFD); if (!(flags & FD_CLOEXEC)) { flags |= FD_CLOEXEC; fcntl(fd, F_SETFD, flags); } } void iv_fd_set_nonblock(int fd) { int flags; flags = fcntl(fd, F_GETFL); if (!(flags & O_NONBLOCK)) { flags |= O_NONBLOCK; fcntl(fd, F_SETFL, flags); } } /* public use ***************************************************************/ const char *iv_poll_method_name(void) { return method != NULL ? method->name : NULL; } void IV_FD_INIT(struct iv_fd *_fd) { struct iv_fd_ *fd = (struct iv_fd_ *)_fd; fd->fd = -1; fd->handler_in = NULL; fd->handler_out = NULL; fd->handler_err = NULL; fd->registered = 0; } static void recompute_wanted_flags(struct iv_fd_ *fd) { int wanted; wanted = 0; if (fd->registered) { if (fd->handler_in != NULL) wanted |= MASKIN; if (fd->handler_out != NULL) wanted |= MASKOUT; if (fd->handler_err != NULL) wanted |= MASKERR; } fd->wanted_bands = wanted; } static void notify_fd(struct iv_state *st, struct iv_fd_ *fd) { recompute_wanted_flags(fd); method->notify_fd(st, fd); } static void iv_fd_register_prologue(struct iv_state *st, struct iv_fd_ *fd) { if (fd->registered) { iv_fatal("iv_fd_register: called with fd which is " "still registered"); } if (fd->fd < 0 || fd->fd >= maxfd) { iv_fatal("iv_fd_register: called with invalid fd %d " "(maxfd=%d)", fd->fd, maxfd); } fd->registered = 1; INIT_IV_LIST_HEAD(&fd->list_active); fd->ready_bands = 0; fd->registered_bands = 0; #if defined(HAVE_SYS_DEVPOLL_H) || defined(HAVE_EPOLL_CREATE) || \ defined(HAVE_KQUEUE) || defined(HAVE_PORT_CREATE) INIT_IV_LIST_HEAD(&fd->list_notify); #endif if (method->register_fd != NULL) method->register_fd(st, fd); } static void iv_fd_register_epilogue(struct iv_state *st, struct iv_fd_ *fd) { int yes; st->numobjs++; st->numfds++; iv_fd_set_cloexec(fd->fd); iv_fd_set_nonblock(fd->fd); yes = 1; setsockopt(fd->fd, SOL_SOCKET, SO_OOBINLINE, &yes, sizeof(yes)); } void iv_fd_register(struct iv_fd *_fd) { struct iv_state *st = iv_get_state(); struct iv_fd_ *fd = (struct iv_fd_ *)_fd; iv_fd_register_prologue(st, fd); notify_fd(st, fd); iv_fd_register_epilogue(st, fd); } int iv_fd_register_try(struct iv_fd *_fd) { struct iv_state *st = iv_get_state(); struct iv_fd_ *fd = (struct iv_fd_ *)_fd; int orig_wanted_bands; int ret; iv_fd_register_prologue(st, fd); recompute_wanted_flags(fd); orig_wanted_bands = fd->wanted_bands; if (!fd->wanted_bands) fd->wanted_bands = MASKIN | MASKOUT; ret = method->notify_fd_sync(st, fd); if (ret) { fd->registered = 0; if (method->unregister_fd != NULL) method->unregister_fd(st, fd); return ret; } if (!orig_wanted_bands) { fd->wanted_bands = 0; method->notify_fd(st, fd); } iv_fd_register_epilogue(st, fd); return 0; } void iv_fd_unregister(struct iv_fd *_fd) { struct iv_state *st = iv_get_state(); struct iv_fd_ *fd = (struct iv_fd_ *)_fd; if (!fd->registered) { iv_fatal("iv_fd_unregister: called with fd which is " "not registered"); } fd->registered = 0; iv_list_del(&fd->list_active); notify_fd(st, fd); if (method->unregister_fd != NULL) method->unregister_fd(st, fd); st->numobjs--; st->numfds--; if (st->handled_fd == fd) st->handled_fd = NULL; } int iv_fd_registered(struct iv_fd *_fd) { struct iv_fd_ *fd = (struct iv_fd_ *)_fd; return fd->registered; } void iv_fd_set_handler_in(struct iv_fd *_fd, void (*handler_in)(void *)) { struct iv_state *st = iv_get_state(); struct iv_fd_ *fd = (struct iv_fd_ *)_fd; if (!fd->registered) { iv_fatal("iv_fd_set_handler_in: called with fd which " "is not registered"); } fd->handler_in = handler_in; notify_fd(st, fd); } void iv_fd_set_handler_out(struct iv_fd *_fd, void (*handler_out)(void *)) { struct iv_state *st = iv_get_state(); struct iv_fd_ *fd = (struct iv_fd_ *)_fd; if (!fd->registered) { iv_fatal("iv_fd_set_handler_out: called with fd which " "is not registered"); } fd->handler_out = handler_out; notify_fd(st, fd); } void iv_fd_set_handler_err(struct iv_fd *_fd, void (*handler_err)(void *)) { struct iv_state *st = iv_get_state(); struct iv_fd_ *fd = (struct iv_fd_ *)_fd; if (!fd->registered) { iv_fatal("iv_fd_set_handler_err: called with fd which " "is not registered"); } fd->handler_err = handler_err; notify_fd(st, fd); } ivykis-0.36.2/src/iv_fd_dev_poll.c000066400000000000000000000136021210744026200170260ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2009 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include "iv_private.h" #include "iv_fd_private.h" #define UPLOAD_BATCH 1024 static int iv_fd_avl_compare(struct iv_avl_node *_a, struct iv_avl_node *_b) { struct iv_fd_ *a = iv_container_of(_a, struct iv_fd_, u.avl_node); struct iv_fd_ *b = iv_container_of(_b, struct iv_fd_, u.avl_node); if (a->fd < b->fd) return -1; if (a->fd > b->fd) return 1; return 0; } static int iv_fd_dev_poll_init(struct iv_state *st) { int poll_fd; #ifdef O_CLOEXEC poll_fd = open("/dev/poll", O_RDWR | O_CLOEXEC); if (poll_fd < 0) return -1; #else poll_fd = open("/dev/poll", O_RDWR); if (poll_fd < 0) return -1; iv_fd_set_cloexec(poll_fd); #endif INIT_IV_AVL_TREE(&st->u.dev_poll.fds, iv_fd_avl_compare); st->u.dev_poll.poll_fd = poll_fd; INIT_IV_LIST_HEAD(&st->u.dev_poll.notify); return 0; } static void xwrite(int fd, const void *buf, size_t count) { while (count) { int ret; do { ret = write(fd, buf, count); } while (ret < 0 && errno == EINTR); if (ret < 0) { iv_fatal("iv_fd_dev_poll_flush_pending: got error " "%d[%s]", errno, strerror(errno)); } buf += ret; count -= ret; } } static int bits_to_poll_mask(int bits) { int mask; mask = 0; if (bits & MASKIN) mask |= POLLIN; if (bits & MASKOUT) mask |= POLLOUT; return mask; } static void iv_fd_dev_poll_flush_pending(struct iv_state *st) { int poll_fd; struct pollfd pfd[UPLOAD_BATCH]; int num; poll_fd = st->u.dev_poll.poll_fd; num = 0; while (!iv_list_empty(&st->u.dev_poll.notify)) { struct iv_list_head *ilh; struct iv_fd_ *fd; if (num > UPLOAD_BATCH - 2) { xwrite(poll_fd, pfd, num * sizeof(pfd[0])); num = 0; } ilh = st->u.dev_poll.notify.next; iv_list_del_init(ilh); fd = iv_list_entry(ilh, struct iv_fd_, list_notify); if (fd->registered_bands & ~fd->wanted_bands) { pfd[num].fd = fd->fd; pfd[num].events = POLLREMOVE; num++; } if (fd->wanted_bands) { pfd[num].fd = fd->fd; pfd[num].events = bits_to_poll_mask(fd->wanted_bands); num++; } fd->registered_bands = fd->wanted_bands; } if (num) xwrite(poll_fd, pfd, num * sizeof(pfd[0])); } static struct iv_fd_ *iv_fd_avl_find(struct iv_avl_tree *root, int fd) { struct iv_avl_node *an; an = root->root; while (an != NULL) { struct iv_fd_ *p; p = iv_container_of(an, struct iv_fd_, u.avl_node); if (fd == p->fd) return p; if (fd < p->fd) an = an->left; else an = an->right; } return NULL; } static void iv_fd_dev_poll_poll(struct iv_state *st, struct iv_list_head *active, struct timespec *to) { struct pollfd batch[st->numfds ? : 1]; struct dvpoll dvp; int ret; int i; iv_fd_dev_poll_flush_pending(st); dvp.dp_fds = batch; dvp.dp_nfds = ARRAY_SIZE(batch); dvp.dp_timeout = 1000 * to->tv_sec + ((to->tv_nsec + 999999) / 1000000); ret = ioctl(st->u.dev_poll.poll_fd, DP_POLL, &dvp); if (ret < 0) { if (errno == EINTR) return; iv_fatal("iv_fd_dev_poll_poll: got error %d[%s]", errno, strerror(errno)); } for (i = 0; i < ret; i++) { struct iv_fd_ *fd; int revents; fd = iv_fd_avl_find(&st->u.dev_poll.fds, batch[i].fd); if (fd == NULL) { iv_fatal("iv_fd_dev_poll_poll: got event for " "unknown fd %d", batch[i].fd); } revents = batch[i].revents; if (revents & (POLLIN | POLLERR | POLLHUP)) iv_fd_make_ready(active, fd, MASKIN); if (revents & (POLLOUT | POLLERR | POLLHUP)) iv_fd_make_ready(active, fd, MASKOUT); if (revents & (POLLERR | POLLHUP)) iv_fd_make_ready(active, fd, MASKERR); } } static void iv_fd_dev_poll_register_fd(struct iv_state *st, struct iv_fd_ *fd) { int ret; ret = iv_avl_tree_insert(&st->u.dev_poll.fds, &fd->u.avl_node); if (ret) { iv_fatal("iv_fd_dev_poll_register_fd: got error %d[%s]", ret, strerror(ret)); } } static void iv_fd_dev_poll_unregister_fd(struct iv_state *st, struct iv_fd_ *fd) { iv_avl_tree_delete(&st->u.dev_poll.fds, &fd->u.avl_node); if (!iv_list_empty(&fd->list_notify)) iv_fd_dev_poll_flush_pending(st); } static void iv_fd_dev_poll_notify_fd(struct iv_state *st, struct iv_fd_ *fd) { iv_list_del_init(&fd->list_notify); if (fd->registered_bands != fd->wanted_bands) iv_list_add_tail(&fd->list_notify, &st->u.dev_poll.notify); } static int iv_fd_dev_poll_notify_fd_sync(struct iv_state *st, struct iv_fd_ *fd) { struct pollfd pfd; int ret; pfd.fd = fd->fd; pfd.events = bits_to_poll_mask(fd->wanted_bands); do { ret = write(st->u.dev_poll.poll_fd, &pfd, sizeof(pfd)); } while (ret < 0 && errno == EINTR); if (ret == sizeof(pfd)) { fd->registered_bands = fd->wanted_bands; return 0; } return -1; } static void iv_fd_dev_poll_deinit(struct iv_state *st) { close(st->u.dev_poll.poll_fd); } struct iv_fd_poll_method iv_fd_poll_method_dev_poll = { .name = "dev_poll", .init = iv_fd_dev_poll_init, .poll = iv_fd_dev_poll_poll, .register_fd = iv_fd_dev_poll_register_fd, .unregister_fd = iv_fd_dev_poll_unregister_fd, .notify_fd = iv_fd_dev_poll_notify_fd, .notify_fd_sync = iv_fd_dev_poll_notify_fd_sync, .deinit = iv_fd_dev_poll_deinit, }; ivykis-0.36.2/src/iv_fd_epoll.c000066400000000000000000000105121210744026200163320ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2009 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include "iv_private.h" #include "iv_fd_private.h" static int iv_fd_epoll_init(struct iv_state *st) { int fd; INIT_IV_LIST_HEAD(&st->u.epoll.notify); #ifdef HAVE_EPOLL_CREATE1 fd = epoll_create1(EPOLL_CLOEXEC); if (fd >= 0) { st->u.epoll.epoll_fd = fd; return 0; } else if (errno != ENOSYS) { return -1; } #endif fd = epoll_create(maxfd); if (fd < 0) return -1; iv_fd_set_cloexec(fd); st->u.epoll.epoll_fd = fd; return 0; } static int bits_to_poll_mask(int bits) { int mask; mask = 0; if (bits & MASKIN) mask |= EPOLLIN; if (bits & MASKOUT) mask |= EPOLLOUT; return mask; } static int __iv_fd_epoll_flush_one(struct iv_state *st, struct iv_fd_ *fd) { int op; struct epoll_event event; int ret; iv_list_del_init(&fd->list_notify); if (fd->registered_bands == fd->wanted_bands) return 0; if (!fd->registered_bands && fd->wanted_bands) op = EPOLL_CTL_ADD; else if (fd->registered_bands && !fd->wanted_bands) op = EPOLL_CTL_DEL; else op = EPOLL_CTL_MOD; event.data.ptr = fd; event.events = bits_to_poll_mask(fd->wanted_bands); do { ret = epoll_ctl(st->u.epoll.epoll_fd, op, fd->fd, &event); } while (ret < 0 && errno == EINTR); if (ret == 0) fd->registered_bands = fd->wanted_bands; return ret; } static void iv_fd_epoll_flush_one(struct iv_state *st, struct iv_fd_ *fd) { if (__iv_fd_epoll_flush_one(st, fd) < 0) { iv_fatal("iv_fd_epoll_flush_one: got error %d[%s]", errno, strerror(errno)); } } static void iv_fd_epoll_flush_pending(struct iv_state *st) { while (!iv_list_empty(&st->u.epoll.notify)) { struct iv_fd_ *fd; fd = iv_list_entry(st->u.epoll.notify.next, struct iv_fd_, list_notify); iv_fd_epoll_flush_one(st, fd); } } static void iv_fd_epoll_poll(struct iv_state *st, struct iv_list_head *active, struct timespec *to) { struct epoll_event batch[st->numfds ? : 1]; int msec; int ret; int i; iv_fd_epoll_flush_pending(st); msec = 1000 * to->tv_sec + ((to->tv_nsec + 999999) / 1000000); ret = epoll_wait(st->u.epoll.epoll_fd, batch, ARRAY_SIZE(batch), msec); if (ret < 0) { if (errno == EINTR) return; iv_fatal("iv_fd_epoll_poll: got error %d[%s]", errno, strerror(errno)); } for (i = 0; i < ret; i++) { struct iv_fd_ *fd; uint32_t events; fd = batch[i].data.ptr; events = batch[i].events; if (events & (EPOLLIN | EPOLLERR | EPOLLHUP)) iv_fd_make_ready(active, fd, MASKIN); if (events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) iv_fd_make_ready(active, fd, MASKOUT); if (events & (EPOLLERR | EPOLLHUP)) iv_fd_make_ready(active, fd, MASKERR); } } static void iv_fd_epoll_unregister_fd(struct iv_state *st, struct iv_fd_ *fd) { if (!iv_list_empty(&fd->list_notify)) iv_fd_epoll_flush_one(st, fd); } static void iv_fd_epoll_notify_fd(struct iv_state *st, struct iv_fd_ *fd) { iv_list_del_init(&fd->list_notify); if (fd->registered_bands != fd->wanted_bands) iv_list_add_tail(&fd->list_notify, &st->u.epoll.notify); } static int iv_fd_epoll_notify_fd_sync(struct iv_state *st, struct iv_fd_ *fd) { return __iv_fd_epoll_flush_one(st, fd); } static void iv_fd_epoll_deinit(struct iv_state *st) { close(st->u.epoll.epoll_fd); } struct iv_fd_poll_method iv_fd_poll_method_epoll = { .name = "epoll", .init = iv_fd_epoll_init, .poll = iv_fd_epoll_poll, .unregister_fd = iv_fd_epoll_unregister_fd, .notify_fd = iv_fd_epoll_notify_fd, .notify_fd_sync = iv_fd_epoll_notify_fd_sync, .deinit = iv_fd_epoll_deinit, }; ivykis-0.36.2/src/iv_fd_kqueue.c000066400000000000000000000154571210744026200165330ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2009 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include "iv_private.h" #include "iv_fd_private.h" #ifndef EVFILT_USER #define EVFILT_USER (-11) #endif #ifndef NOTE_TRIGGER #define NOTE_TRIGGER 0x01000000 #endif #define UPLOAD_BATCH 1024 static int iv_fd_kqueue_init(struct iv_state *st) { int kqueue_fd; kqueue_fd = kqueue(); if (kqueue_fd < 0) return -1; iv_fd_set_cloexec(kqueue_fd); st->u.kqueue.kqueue_fd = kqueue_fd; INIT_IV_LIST_HEAD(&st->u.kqueue.notify); return 0; } static void iv_fd_kqueue_queue_one(struct kevent *kev, int *_num, struct iv_fd_ *fd) { int num; int wanted; int regd; iv_list_del_init(&fd->list_notify); num = *_num; wanted = fd->wanted_bands; regd = fd->registered_bands; if (!(wanted & MASKIN) && (regd & MASKIN)) { EV_SET(&kev[num], fd->fd, EVFILT_READ, EV_DELETE, 0, 0, (void *)(intptr_t)fd); num++; } else if ((wanted & MASKIN) && !(regd & MASKIN)) { EV_SET(&kev[num], fd->fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, (void *)(intptr_t)fd); num++; } if (!(wanted & MASKOUT) && (regd & MASKOUT)) { EV_SET(&kev[num], fd->fd, EVFILT_WRITE, EV_DELETE, 0, 0, (void *)(intptr_t)fd); num++; } else if ((wanted & MASKOUT) && !(regd & MASKOUT)) { EV_SET(&kev[num], fd->fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, (void *)(intptr_t)fd); num++; } *_num = num; } static int __kevent_retry(int kq, const struct kevent *changelist, int nchanges) { struct timespec to = { 0, 0 }; int ret; do { ret = kevent(kq, changelist, nchanges, NULL, 0, &to); } while (ret < 0 && errno == EINTR); return ret; } static void kevent_retry(char *name, struct iv_state *st, const struct kevent *changelist, int nchanges) { if (__kevent_retry(st->u.kqueue.kqueue_fd, changelist, nchanges) < 0) iv_fatal("%s: got error %d[%s]", name, errno, strerror(errno)); } static void iv_fd_kqueue_upload(struct iv_state *st, struct kevent *kev, int size, int *num) { *num = 0; while (!iv_list_empty(&st->u.kqueue.notify)) { struct iv_fd_ *fd; if (*num > size - 2) { kevent_retry("iv_fd_kqueue_upload", st, kev, *num); *num = 0; } fd = iv_list_entry(st->u.kqueue.notify.next, struct iv_fd_, list_notify); iv_fd_kqueue_queue_one(kev, num, fd); fd->registered_bands = fd->wanted_bands; } } static void iv_fd_kqueue_poll(struct iv_state *st, struct iv_list_head *active, struct timespec *to) { struct kevent kev[UPLOAD_BATCH]; int num; struct kevent batch[st->numfds ? : 1]; int ret; int run_events; int i; iv_fd_kqueue_upload(st, kev, UPLOAD_BATCH, &num); ret = kevent(st->u.kqueue.kqueue_fd, kev, num, batch, ARRAY_SIZE(batch), to); if (ret < 0) { if (errno == EINTR) return; iv_fatal("iv_fd_kqueue_poll: got error %d[%s]", errno, strerror(errno)); } run_events = 0; for (i = 0; i < ret; i++) { struct iv_fd_ *fd; if (batch[i].filter == EVFILT_USER) { run_events = 1; continue; } if (batch[i].flags & EV_ERROR) { int err = batch[i].data; int fd = batch[i].ident; iv_fatal("iv_fd_kqueue_poll: got error %d[%s] " "polling fd %d", err, strerror(err), fd); } fd = (void *)batch[i].udata; if (batch[i].filter == EVFILT_READ) { iv_fd_make_ready(active, fd, MASKIN); } else if (batch[i].filter == EVFILT_WRITE) { iv_fd_make_ready(active, fd, MASKOUT); } else { iv_fatal("iv_fd_kqueue_poll: got message from " "filter %d", batch[i].filter); } } if (run_events) iv_event_run_pending_events(); } static void iv_fd_kqueue_upload_all(struct iv_state *st) { struct kevent kev[UPLOAD_BATCH]; int num; iv_fd_kqueue_upload(st, kev, UPLOAD_BATCH, &num); if (num) kevent_retry("iv_fd_kqueue_upload_all", st, kev, num); } static void iv_fd_kqueue_unregister_fd(struct iv_state *st, struct iv_fd_ *fd) { if (!iv_list_empty(&fd->list_notify)) iv_fd_kqueue_upload_all(st); } static void iv_fd_kqueue_notify_fd(struct iv_state *st, struct iv_fd_ *fd) { iv_list_del_init(&fd->list_notify); if (fd->registered_bands != fd->wanted_bands) iv_list_add_tail(&fd->list_notify, &st->u.kqueue.notify); } static int iv_fd_kqueue_notify_fd_sync(struct iv_state *st, struct iv_fd_ *fd) { struct kevent kev; int ret; if (fd->wanted_bands & MASKIN) { EV_SET(&kev, fd->fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, (void *)(intptr_t)fd); ret = __kevent_retry(st->u.kqueue.kqueue_fd, &kev, 1); if (ret == 0) { fd->registered_bands |= MASKIN; return 0; } } if (fd->wanted_bands & MASKOUT) { EV_SET(&kev, fd->fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, (void *)(intptr_t)fd); ret = __kevent_retry(st->u.kqueue.kqueue_fd, &kev, 1); if (ret == 0) { fd->registered_bands |= MASKOUT; return 0; } } return -1; } static void iv_fd_kqueue_deinit(struct iv_state *st) { close(st->u.kqueue.kqueue_fd); } static int iv_fd_kqueue_event_rx_on(struct iv_state *st) { struct kevent add; int ret; EV_SET(&add, (intptr_t)st, EVFILT_USER, EV_ADD | EV_CLEAR | EV_ENABLE, 0, 0, NULL); ret = __kevent_retry(st->u.kqueue.kqueue_fd, &add, 1); if (ret == 0) st->numobjs++; return ret; } static void iv_fd_kqueue_event_rx_off(struct iv_state *st) { struct kevent delete; EV_SET(&delete, (intptr_t)st, EVFILT_USER, EV_DELETE, 0, 0, NULL); kevent_retry("iv_fd_kqueue_event_rx_off", st, &delete, 1); st->numobjs--; } static void iv_fd_kqueue_event_send(struct iv_state *dest) { struct kevent send; EV_SET(&send, (intptr_t)dest, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); kevent_retry("iv_fd_kqueue_event_send", dest, &send, 1); } struct iv_fd_poll_method iv_fd_poll_method_kqueue = { .name = "kqueue", .init = iv_fd_kqueue_init, .poll = iv_fd_kqueue_poll, .unregister_fd = iv_fd_kqueue_unregister_fd, .notify_fd = iv_fd_kqueue_notify_fd, .notify_fd_sync = iv_fd_kqueue_notify_fd_sync, .deinit = iv_fd_kqueue_deinit, .event_rx_on = iv_fd_kqueue_event_rx_on, .event_rx_off = iv_fd_kqueue_event_rx_off, .event_send = iv_fd_kqueue_event_send, }; ivykis-0.36.2/src/iv_fd_poll.c000066400000000000000000000100751210744026200161710ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2009 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include "iv_private.h" #include "iv_fd_private.h" static int iv_fd_poll_init(struct iv_state *st) { st->u.poll.pfds = malloc(maxfd * sizeof(struct pollfd)); if (st->u.poll.pfds == NULL) return -1; st->u.poll.fds = malloc(maxfd * sizeof(struct iv_fd_ *)); if (st->u.poll.fds == NULL) { free(st->u.poll.pfds); return -1; } st->u.poll.num_regd_fds = 0; return 0; } static void iv_fd_poll_poll(struct iv_state *st, struct iv_list_head *active, struct timespec *to) { int ret; int i; #if _AIX /* * AIX sometimes leaves errno uninitialized even if poll * returns -1. */ errno = EINTR; #endif ret = poll(st->u.poll.pfds, st->u.poll.num_regd_fds, 1000 * to->tv_sec + ((to->tv_nsec + 999999) / 1000000)); if (ret < 0) { if (errno == EINTR) return; iv_fatal("iv_fd_poll_poll: got error %d[%s]", errno, strerror(errno)); } for (i = 0; i < st->u.poll.num_regd_fds; i++) { struct iv_fd_ *fd; int revents; fd = st->u.poll.fds[i]; revents = st->u.poll.pfds[i].revents; if (revents & (POLLIN | POLLERR | POLLHUP)) iv_fd_make_ready(active, fd, MASKIN); if (revents & (POLLOUT | POLLERR | POLLHUP)) iv_fd_make_ready(active, fd, MASKOUT); if (revents & (POLLERR | POLLHUP)) iv_fd_make_ready(active, fd, MASKERR); } } static void iv_fd_poll_register_fd(struct iv_state *st, struct iv_fd_ *fd) { fd->u.index = -1; } static int bits_to_poll_mask(int bits) { int mask; mask = 0; if (bits & MASKIN) mask |= POLLIN | POLLHUP; if (bits & MASKOUT) mask |= POLLOUT | POLLHUP; if (bits & MASKERR) mask |= POLLHUP; return mask; } static void iv_fd_poll_notify_fd(struct iv_state *st, struct iv_fd_ *fd) { if (fd->registered_bands == fd->wanted_bands) return; if (fd->u.index == -1 && fd->wanted_bands) { fd->u.index = st->u.poll.num_regd_fds++; st->u.poll.pfds[fd->u.index].fd = fd->fd; st->u.poll.pfds[fd->u.index].events = bits_to_poll_mask(fd->wanted_bands); st->u.poll.fds[fd->u.index] = fd; } else if (fd->u.index != -1 && !fd->wanted_bands) { st->u.poll.num_regd_fds--; if (fd->u.index != st->u.poll.num_regd_fds) { struct iv_fd_ *last; st->u.poll.pfds[fd->u.index] = st->u.poll.pfds[st->u.poll.num_regd_fds]; last = st->u.poll.fds[st->u.poll.num_regd_fds]; last->u.index = fd->u.index; st->u.poll.fds[fd->u.index] = last; } fd->u.index = -1; } else { st->u.poll.pfds[fd->u.index].events = bits_to_poll_mask(fd->wanted_bands); } fd->registered_bands = fd->wanted_bands; } static int iv_fd_poll_notify_fd_sync(struct iv_state *st, struct iv_fd_ *fd) { struct pollfd pfd; int ret; pfd.fd = fd->fd; pfd.events = POLLIN | POLLOUT | POLLHUP; do { ret = poll(&pfd, 1, 0); } while (ret < 0 && errno == EINTR); if (ret < 0 || (pfd.revents & POLLNVAL)) return -1; iv_fd_poll_notify_fd(st, fd); return 0; } static void iv_fd_poll_deinit(struct iv_state *st) { free(st->u.poll.fds); free(st->u.poll.pfds); } struct iv_fd_poll_method iv_fd_poll_method_poll = { .name = "poll", .init = iv_fd_poll_init, .poll = iv_fd_poll_poll, .register_fd = iv_fd_poll_register_fd, .notify_fd = iv_fd_poll_notify_fd, .notify_fd_sync = iv_fd_poll_notify_fd_sync, .deinit = iv_fd_poll_deinit, }; ivykis-0.36.2/src/iv_fd_port.c000066400000000000000000000123131210744026200162040ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2011 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include "iv_private.h" #include "iv_fd_private.h" #define PORTEV_NUM 1024 static int iv_fd_port_init(struct iv_state *st) { int fd; fd = port_create(); if (fd < 0) return -1; iv_fd_set_cloexec(fd); st->u.port.port_fd = fd; INIT_IV_LIST_HEAD(&st->u.port.notify); return 0; } static int bits_to_poll_mask(int bits) { int mask; mask = 0; if (bits & MASKIN) mask |= POLLIN; if (bits & MASKOUT) mask |= POLLOUT; return mask; } static int __iv_fd_port_upload_one(struct iv_state *st, struct iv_fd_ *fd) { int ret; iv_list_del_init(&fd->list_notify); if (fd->wanted_bands) { ret = port_associate(st->u.port.port_fd, PORT_SOURCE_FD, fd->fd, bits_to_poll_mask(fd->wanted_bands), fd); } else { ret = port_dissociate(st->u.port.port_fd, PORT_SOURCE_FD, fd->fd); } if (ret == 0) fd->registered_bands = fd->wanted_bands; return ret; } static void iv_fd_port_upload_one(struct iv_state *st, struct iv_fd_ *fd) { if (__iv_fd_port_upload_one(st, fd) < 0) { iv_fatal("iv_fd_port_upload_one: got error %d[%s]", errno, strerror(errno)); } } static void iv_fd_port_upload(struct iv_state *st) { while (!iv_list_empty(&st->u.port.notify)) { struct iv_fd_ *fd; fd = iv_list_entry(st->u.port.notify.next, struct iv_fd_, list_notify); iv_fd_port_upload_one(st, fd); } } static void iv_fd_port_poll(struct iv_state *st, struct iv_list_head *active, struct timespec *to) { int run_events; unsigned int nget; port_event_t pe[PORTEV_NUM]; int ret; int i; iv_fd_port_upload(st); run_events = 0; poll_more: nget = 1; /* * If we get EINTR from port_getn(), no events are returned * and nget will not have been updated, but if we get ETIME, * events may be returned, and nget will be set to the number * of events in the array, and we need to process those * events as usual. */ ret = port_getn(st->u.port.port_fd, pe, PORTEV_NUM, &nget, to); if (ret < 0 && errno != ETIME) { if (errno == EINTR) return; iv_fatal("iv_fd_port_poll: got error %d[%s]", errno, strerror(errno)); } for (i = 0; i < nget; i++) { int source; source = pe[i].portev_source; if (source == PORT_SOURCE_FD) { int revents; struct iv_fd_ *fd; revents = pe[i].portev_events; fd = pe[i].portev_user; if (revents & (POLLIN | POLLERR | POLLHUP)) iv_fd_make_ready(active, fd, MASKIN); if (revents & (POLLOUT | POLLERR | POLLHUP)) iv_fd_make_ready(active, fd, MASKOUT); if (revents & (POLLERR | POLLHUP)) iv_fd_make_ready(active, fd, MASKERR); fd->registered_bands = 0; iv_list_del_init(&fd->list_notify); if (fd->wanted_bands) { iv_list_add_tail(&fd->list_notify, &st->u.port.notify); } } else if (source == PORT_SOURCE_USER) { run_events = 1; } else { iv_fatal("iv_fd_port_poll: received event " "from unknown source %d", source); } } if (nget == PORTEV_NUM) { to->tv_sec = 0; to->tv_nsec = 0; goto poll_more; } if (run_events) iv_event_run_pending_events(); } static void iv_fd_port_unregister_fd(struct iv_state *st, struct iv_fd_ *fd) { if (!iv_list_empty(&fd->list_notify)) iv_fd_port_upload_one(st, fd); } static void iv_fd_port_notify_fd(struct iv_state *st, struct iv_fd_ *fd) { iv_list_del_init(&fd->list_notify); if (fd->registered_bands != fd->wanted_bands) iv_list_add_tail(&fd->list_notify, &st->u.port.notify); } static int iv_fd_port_notify_fd_sync(struct iv_state *st, struct iv_fd_ *fd) { return __iv_fd_port_upload_one(st, fd); } static void iv_fd_port_deinit(struct iv_state *st) { close(st->u.port.port_fd); } static int iv_fd_port_event_rx_on(struct iv_state *st) { st->numobjs++; return 0; } static void iv_fd_port_event_rx_off(struct iv_state *st) { st->numobjs--; } static void iv_fd_port_event_send(struct iv_state *dest) { if (port_send(dest->u.port.port_fd, 0, NULL) < 0) { iv_fatal("iv_fd_port_event_send: port_send got " "error %d[%s]", errno, strerror(errno)); } } struct iv_fd_poll_method iv_fd_poll_method_port = { .name = "port", .init = iv_fd_port_init, .poll = iv_fd_port_poll, .unregister_fd = iv_fd_port_unregister_fd, .notify_fd = iv_fd_port_notify_fd, .notify_fd_sync = iv_fd_port_notify_fd_sync, .deinit = iv_fd_port_deinit, .event_rx_on = iv_fd_port_event_rx_on, .event_rx_off = iv_fd_port_event_rx_off, .event_send = iv_fd_port_event_send, }; ivykis-0.36.2/src/iv_fd_private.h000066400000000000000000000071761210744026200167120ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2009, 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #define MASKIN 1 #define MASKOUT 2 #define MASKERR 4 struct iv_fd_ { /* * User data. */ int fd; void *cookie; void (*handler_in)(void *); void (*handler_out)(void *); void (*handler_err)(void *); /* * If this fd gathered any events during this polling round, * fd->list_active will be on iv_main()'s active list, and * fd->ready_bands will indicate which bands are currently * active. */ struct iv_list_head list_active; unsigned ready_bands:3; /* * Reflects whether the fd has been registered with * iv_fd_register(). Will be zero in ->notify_fd() if the * fd is being unregistered. */ unsigned registered:1; /* * ->wanted_bands is set by the ivykis core to indicate * which bands currenty have handlers registered for them. */ unsigned wanted_bands:3; /* * ->registered_bands is maintained by the poll method to * indicate which bands are currently registered with the * kernel, so that the ivykis core knows when to call * the poll method's ->notify_fd() on an fd. */ unsigned registered_bands:3; #if defined(HAVE_SYS_DEVPOLL_H) || defined(HAVE_EPOLL_CREATE) || \ defined(HAVE_KQUEUE) || defined(HAVE_PORT_CREATE) /* * ->list_notify is used by poll methods that defer updating * kernel registrations to ->poll() time. */ struct iv_list_head list_notify; #endif /* * This is for state internal to some of the poll methods: * ->avl_node is used by the /dev/poll method to maintain an * internal fd tree, and ->index is used by iv_fd_poll to * maintain the index of this fd in the list of pollfds. */ union { #ifdef HAVE_SYS_DEVPOLL_H struct iv_avl_node avl_node; #endif int index; } u; }; struct iv_fd_poll_method { char *name; int (*init)(struct iv_state *st); void (*poll)(struct iv_state *st, struct iv_list_head *active, struct timespec *to); void (*register_fd)(struct iv_state *st, struct iv_fd_ *fd); void (*unregister_fd)(struct iv_state *st, struct iv_fd_ *fd); void (*notify_fd)(struct iv_state *st, struct iv_fd_ *fd); int (*notify_fd_sync)(struct iv_state *st, struct iv_fd_ *fd); void (*deinit)(struct iv_state *st); int (*event_rx_on)(struct iv_state *st); void (*event_rx_off)(struct iv_state *st); void (*event_send)(struct iv_state *dest); }; extern int maxfd; extern struct iv_fd_poll_method *method; extern struct iv_fd_poll_method iv_fd_poll_method_dev_poll; extern struct iv_fd_poll_method iv_fd_poll_method_epoll; extern struct iv_fd_poll_method iv_fd_poll_method_kqueue; extern struct iv_fd_poll_method iv_fd_poll_method_poll; extern struct iv_fd_poll_method iv_fd_poll_method_port; /* iv_event_posix.c */ void iv_event_run_pending_events(void); /* iv_fd.c */ void iv_fd_make_ready(struct iv_list_head *active, struct iv_fd_ *fd, int bands); void iv_fd_set_cloexec(int fd); void iv_fd_set_nonblock(int fd); ivykis-0.36.2/src/iv_fd_pump.c000066400000000000000000000165131210744026200162070ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2011 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include "config.h" #include "iv_fd_pump.h" /* thread state handling ****************************************************/ struct iv_fd_pump_thr_info { int num_bufs; struct iv_list_head bufs; }; static void buf_purge(struct iv_fd_pump_thr_info *tinfo); static void iv_fd_pump_tls_init_thread(void *_tinfo) { struct iv_fd_pump_thr_info *tinfo = _tinfo; tinfo->num_bufs = 0; INIT_IV_LIST_HEAD(&tinfo->bufs); } static void iv_fd_pump_tls_deinit_thread(void *_tinfo) { struct iv_fd_pump_thr_info *tinfo = _tinfo; buf_purge(tinfo); } static struct iv_tls_user iv_fd_pump_tls_user = { .sizeof_state = sizeof(struct iv_fd_pump_thr_info), .init_thread = iv_fd_pump_tls_init_thread, .deinit_thread = iv_fd_pump_tls_deinit_thread, }; static void iv_fd_pump_tls_init(void) __attribute__((constructor)); static void iv_fd_pump_tls_init(void) { iv_tls_user_register(&iv_fd_pump_tls_user); } /* buffer management ********************************************************/ #define MAX_CACHED_BUFS 20 #define BUF_SIZE 4096 #ifndef HAVE_SPLICE #define splice_available 0 #define splice(...) -1 #ifndef FIONREAD #define FIONREAD 0 #endif #else static int splice_available = -1; #endif struct iv_fd_pump_buf { struct iv_list_head list; union { unsigned char buf[0]; int pfd[2]; } u; }; static struct iv_fd_pump_buf *buf_alloc(void) { int size; struct iv_fd_pump_buf *buf; if (!splice_available) size = sizeof(struct iv_list_head) + BUF_SIZE; else size = sizeof(struct iv_fd_pump_buf); buf = malloc(size); if (buf != NULL && splice_available && pipe(buf->u.pfd) < 0) { free(buf); buf = NULL; } return buf; } static void __buf_free(struct iv_fd_pump_buf *buf) { if (splice_available) { close(buf->u.pfd[0]); close(buf->u.pfd[1]); } free(buf); } static void buf_put(struct iv_fd_pump_buf *buf, int bytes) { struct iv_fd_pump_thr_info *tinfo; if (splice_available && bytes) { __buf_free(buf); return; } tinfo = iv_tls_user_ptr(&iv_fd_pump_tls_user); if (tinfo->num_bufs < MAX_CACHED_BUFS) { tinfo->num_bufs++; iv_list_add(&buf->list, &tinfo->bufs); } else { __buf_free(buf); } } static void check_splice_available(void) { #ifdef HAVE_SPLICE struct iv_fd_pump_buf *b0; struct iv_fd_pump_buf *b1; int ret; splice_available = 1; b0 = buf_alloc(); if (b0 == NULL) { splice_available = 0; return; } b1 = buf_alloc(); if (b1 == NULL) { __buf_free(b0); splice_available = 0; return; } ret = splice(b0->u.pfd[0], NULL, b1->u.pfd[1], NULL, 1, SPLICE_F_NONBLOCK); if (ret < 0 && errno == EAGAIN) { buf_put(b1, 0); buf_put(b0, 0); } else { __buf_free(b0); __buf_free(b1); splice_available = 0; } #endif } static struct iv_fd_pump_buf *__buf_dequeue(struct iv_fd_pump_thr_info *tinfo) { if (!iv_list_empty(&tinfo->bufs)) { struct iv_list_head *ilh; tinfo->num_bufs--; ilh = tinfo->bufs.next; iv_list_del(ilh); return iv_container_of(ilh, struct iv_fd_pump_buf, list); } return NULL; } static struct iv_fd_pump_buf *buf_get(void) { struct iv_fd_pump_thr_info *tinfo = iv_tls_user_ptr(&iv_fd_pump_tls_user); struct iv_fd_pump_buf *buf; buf = __buf_dequeue(tinfo); if (buf == NULL) buf = buf_alloc(); return buf; } static void buf_purge(struct iv_fd_pump_thr_info *tinfo) { struct iv_fd_pump_buf *buf; while ((buf = __buf_dequeue(tinfo)) != NULL) __buf_free(buf); } /* iv_fd_pump ***************************************************************/ static struct iv_fd_pump_buf *iv_fd_pump_buf(struct iv_fd_pump *ip) { return (struct iv_fd_pump_buf *)ip->buf; } void iv_fd_pump_init(struct iv_fd_pump *ip) { if (splice_available == -1) check_splice_available(); ip->buf = NULL; ip->bytes = 0; ip->full = 0; ip->saw_fin = 0; ip->set_bands(ip->cookie, 1, 0); } void iv_fd_pump_destroy(struct iv_fd_pump *ip) { struct iv_fd_pump_buf *buf = iv_fd_pump_buf(ip); if (ip->saw_fin != 2) ip->set_bands(ip->cookie, 0, 0); if (buf != NULL) { buf_put(buf, ip->bytes); ip->buf = NULL; } } static int iv_fd_pump_try_input(struct iv_fd_pump *ip) { struct iv_fd_pump_buf *buf = iv_fd_pump_buf(ip); int ret; if (buf == NULL) { buf = buf_get(); if (buf == NULL) return -1; ip->buf = (void *)buf; } do { if (!splice_available) { ret = read(ip->from_fd, buf->u.buf + ip->bytes, BUF_SIZE - ip->bytes); } else { ret = splice(ip->from_fd, NULL, buf->u.pfd[1], NULL, 1048576, SPLICE_F_NONBLOCK); } } while (ret < 0 && errno == EINTR); if (ret < 0) { if (errno != EAGAIN) return -1; if (splice_available && ip->bytes) { int bytes = 1; ioctl(ip->from_fd, FIONREAD, &bytes); if (bytes > 0) ip->full = 1; } return 0; } if (ret == 0) { ip->saw_fin = 1; if (!ip->bytes) { if (ip->flags & IV_FD_PUMP_FLAG_RELAY_EOF) shutdown(ip->to_fd, SHUT_WR); ip->saw_fin = 2; } return 0; } ip->bytes += ret; if (!splice_available && ip->bytes == BUF_SIZE) ip->full = 1; return 0; } static int iv_fd_pump_try_output(struct iv_fd_pump *ip) { struct iv_fd_pump_buf *buf = iv_fd_pump_buf(ip); int ret; do { if (!splice_available) { ret = write(ip->to_fd, buf->u.buf, ip->bytes); } else { ret = splice(buf->u.pfd[0], NULL, ip->to_fd, NULL, ip->bytes, 0); } } while (ret < 0 && errno == EINTR); if (ret <= 0) return (ret < 0 && errno == EAGAIN) ? 0 : -1; ip->full = 0; ip->bytes -= ret; if (!splice_available) memmove(buf->u.buf, buf->u.buf + ret, ip->bytes); if (!ip->bytes && ip->saw_fin == 1) { if (ip->flags & IV_FD_PUMP_FLAG_RELAY_EOF) shutdown(ip->to_fd, SHUT_WR); ip->saw_fin = 2; } return 0; } static int __iv_fd_pump_pump(struct iv_fd_pump *ip) { if (!ip->full && ip->saw_fin == 0) { if (iv_fd_pump_try_input(ip)) return -1; } if (ip->bytes || ip->saw_fin == 1) { if (iv_fd_pump_try_output(ip)) return -1; } switch (ip->saw_fin) { case 0: ip->set_bands(ip->cookie, !ip->full, !!ip->bytes); return 1; case 1: ip->set_bands(ip->cookie, 0, 1); return 1; case 2: ip->set_bands(ip->cookie, 0, 0); return 0; } iv_fatal("iv_fd_pump_pump: saw_fin == %d", ip->saw_fin); } int iv_fd_pump_pump(struct iv_fd_pump *ip) { int ret; ret = __iv_fd_pump_pump(ip); if (ret < 0 || !ip->bytes) { struct iv_fd_pump_buf *buf = iv_fd_pump_buf(ip); if (buf != NULL) { buf_put(buf, ip->bytes); ip->buf = NULL; } } return ret; } int iv_fd_pump_is_done(struct iv_fd_pump *ip) { return !!(ip->saw_fin == 2); } ivykis-0.36.2/src/iv_handle.c000066400000000000000000000152701210744026200160070ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include "iv_private.h" #include "iv_handle_private.h" void iv_handle_init(struct iv_state *st) { st->wait = CreateEvent(NULL, FALSE, FALSE, NULL); if (st->wait == NULL) iv_fatal("iv_handle_init: CreateEvent failed"); st->thread_stop = CreateEvent(NULL, FALSE, FALSE, NULL); if (st->thread_stop == NULL) iv_fatal("iv_handle_init: CreateEvent failed"); INIT_IV_LIST_HEAD(&st->handles); InitializeCriticalSection(&st->active_handle_list_lock); INIT_IV_LIST_HEAD(&st->active_with_handler); INIT_IV_LIST_HEAD(&st->active_without_handler); st->handled_handle = NULL; } static void iv_handle_stop_poll_thread(struct iv_state *st, struct iv_handle_ *h) { DWORD ret; SetEvent(h->signal_handle); do { ret = WaitForSingleObjectEx(st->thread_stop, INFINITE, TRUE); } while (ret == WAIT_IO_COMPLETION); if (ret != WAIT_OBJECT_0) { iv_fatal("iv_handle_stop_poll_thread: " "WaitForSingleObjectEx fail"); } } void iv_handle_deinit(struct iv_state *st) { while (!iv_list_empty(&st->handles)) { struct iv_handle_ *h; h = iv_list_entry(st->handles.next, struct iv_handle_, list); iv_list_del_init(&h->list); iv_handle_stop_poll_thread(st, h); } CloseHandle(st->wait); CloseHandle(st->thread_stop); DeleteCriticalSection(&st->active_handle_list_lock); } void iv_handle_poll_and_run(struct iv_state *st, struct timespec *to) { struct iv_list_head handles; EnterCriticalSection(&st->active_handle_list_lock); if (iv_list_empty(&st->active_with_handler)) { DWORD msec; DWORD ret; msec = 1000 * to->tv_sec + (to->tv_nsec + 999999) / 1000000; LeaveCriticalSection(&st->active_handle_list_lock); ret = WaitForSingleObjectEx(st->wait, msec, TRUE); EnterCriticalSection(&st->active_handle_list_lock); if (ret != WAIT_OBJECT_0 && ret != WAIT_IO_COMPLETION && ret != WAIT_TIMEOUT) { iv_fatal("iv_handle_poll_and_run: " "WaitForSingleObjectEx returned %x", (int)ret); } __iv_invalidate_now(st); } __iv_list_steal_elements(&st->active_with_handler, &handles); LeaveCriticalSection(&st->active_handle_list_lock); while (!iv_list_empty(&handles)) { struct iv_handle_ *h; h = iv_list_entry(handles.next, struct iv_handle_, list_active); iv_list_del_init(&h->list_active); st->handled_handle = h; h->handler(h->cookie); if (st->handled_handle == h) { SetEvent(h->signal_handle); st->handled_handle = NULL; } } } void IV_HANDLE_INIT(struct iv_handle *_h) { struct iv_handle_ *h = (struct iv_handle_ *)_h; INIT_IV_LIST_HEAD(&h->list); } static DWORD WINAPI iv_handle_poll_thread(void *_h) { struct iv_handle_ *h = (struct iv_handle_ *)_h; struct iv_state *st = h->st; HANDLE hnd[2]; int sig; hnd[0] = h->signal_handle; hnd[1] = h->handle; sig = 0; EnterCriticalSection(&st->active_handle_list_lock); while (!iv_list_empty(&h->list)) { DWORD num; DWORD ret; struct iv_list_head *list; num = iv_list_empty(&h->list_active) ? 2 : 1; LeaveCriticalSection(&st->active_handle_list_lock); if (sig) { sig = 0; SetEvent(st->wait); } ret = WaitForMultipleObjectsEx(num, hnd, FALSE, INFINITE, FALSE); EnterCriticalSection(&st->active_handle_list_lock); if (ret == WAIT_OBJECT_0) continue; if (ret != WAIT_OBJECT_0 + 1 && ret != WAIT_ABANDONED_0 + 1) { iv_fatal("iv_handle_poll_thread(%d): %x", (int)(ULONG_PTR)h->handle, (int)ret); } if (h->handler != NULL) { list = &st->active_with_handler; if (iv_list_empty(list)) sig = 1; } else { list = &st->active_without_handler; } iv_list_add_tail(&h->list_active, list); } LeaveCriticalSection(&st->active_handle_list_lock); SetEvent(st->thread_stop); return 0; } void iv_handle_register(struct iv_handle *_h) { struct iv_state *st = iv_get_state(); struct iv_handle_ *h = (struct iv_handle_ *)_h; HANDLE t; if (!iv_list_empty(&h->list)) { iv_fatal("iv_handle_register: called with handle " "which is still registered"); } iv_list_add_tail(&h->list, &st->handles); INIT_IV_LIST_HEAD(&h->list_active); h->st = st; h->signal_handle = CreateEvent(NULL, FALSE, FALSE, NULL); if (h->signal_handle == NULL) iv_fatal("iv_handle_register: CreateEvent failed"); t = CreateThread(NULL, 0, iv_handle_poll_thread, (void *)h, 0, NULL); if (t == NULL) iv_fatal("iv_handle_register: CreateThread failed"); CloseHandle(t); st->numobjs++; } void iv_handle_unregister(struct iv_handle *_h) { struct iv_handle_ *h = (struct iv_handle_ *)_h; struct iv_state *st = h->st; if (iv_list_empty(&h->list)) { iv_fatal("iv_handle_unregister: called with handle " "which is not registered"); } iv_list_del_init(&h->list); iv_handle_stop_poll_thread(st, h); if (!iv_list_empty(&h->list_active)) { EnterCriticalSection(&st->active_handle_list_lock); iv_list_del_init(&h->list_active); LeaveCriticalSection(&st->active_handle_list_lock); } h->st = NULL; CloseHandle(h->signal_handle); st->numobjs--; if (st->handled_handle == h) st->handled_handle = NULL; } int iv_handle_registered(struct iv_handle *_h) { struct iv_handle_ *h = (struct iv_handle_ *)_h; return !iv_list_empty(&h->list); } static void iv_handle_move_to_list(struct iv_handle_ *h, struct iv_list_head *list) { iv_list_del(&h->list_active); iv_list_add_tail(&h->list_active, list); } void iv_handle_set_handler(struct iv_handle *_h, void (*handler)(void *)) { struct iv_handle_ *h = (struct iv_handle_ *)_h; struct iv_state *st = h->st; if (iv_list_empty(&h->list)) { iv_fatal("iv_handle_set_handler: called with handle " "which is not registered"); } EnterCriticalSection(&st->active_handle_list_lock); if (!iv_list_empty(&h->list_active)) { if (h->handler == NULL && handler != NULL) iv_handle_move_to_list(h, &st->active_with_handler); else if (h->handler != NULL && handler == NULL) iv_handle_move_to_list(h, &st->active_without_handler); } h->handler = handler; LeaveCriticalSection(&st->active_handle_list_lock); } ivykis-0.36.2/src/iv_handle_private.h000066400000000000000000000020601210744026200175370ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ struct iv_handle_ { /* * User data. */ HANDLE handle; void *cookie; void (*handler)(void *); /* * Private data. */ struct iv_list_head list; struct iv_list_head list_active; struct iv_state *st; HANDLE signal_handle; }; ivykis-0.36.2/src/iv_inotify.c000066400000000000000000000072131210744026200162330ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2008 - 2011 Ronald Huizer * Dedicated to Kanna Ishihara. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include static struct iv_inotify_watch *__find_watch(struct iv_inotify *this, int wd) { struct iv_avl_node *an; an = this->watches.root; while (an != NULL) { struct iv_inotify_watch *w; w = iv_container_of(an, struct iv_inotify_watch, an); if (wd == w->wd) return w; if (wd < w->wd) an = an->left; else an = an->right; } return NULL; } static void iv_inotify_got_event(void *_this) { struct iv_inotify *this = (struct iv_inotify *)_this; uint8_t event_queue[65536]; ssize_t ret; void *curr; void *end; do { ret = read(this->fd.fd, event_queue, sizeof(event_queue)); } while (ret == -1 && errno == EINTR); if (ret <= 0) { if (ret == 0) { iv_fatal("iv_inotify: reading from inotify fd " "returned zero"); } else if (errno != EAGAIN) { iv_fatal("iv_inotify: reading from inotify fd " "returned error %d[%s]", errno, strerror(errno)); } return; } this->term = (void **)&this; curr = event_queue; end = event_queue + ret; while (curr < end) { struct inotify_event *event = curr; struct iv_inotify_watch *w; w = __find_watch(this, event->wd); if (w != NULL) { if (event->mask & IN_IGNORED || w->mask & IN_ONESHOT) iv_avl_tree_delete(&this->watches, &w->an); w->handler(w->cookie, event); } curr += event->len + sizeof(struct inotify_event); if (this == NULL) break; } if (this != NULL) this->term = NULL; } static int __iv_inotify_watch_compare(struct iv_avl_node *_a, struct iv_avl_node *_b) { struct iv_inotify_watch *a = iv_container_of(_a, struct iv_inotify_watch, an); struct iv_inotify_watch *b = iv_container_of(_b, struct iv_inotify_watch, an); if (a->wd < b->wd) return -1; if (a->wd > b->wd) return 1; return 0; } int iv_inotify_register(struct iv_inotify *this) { int fd; fd = inotify_init(); if (fd == -1) return -1; IV_FD_INIT(&this->fd); this->fd.fd = fd; this->fd.cookie = this; this->fd.handler_in = iv_inotify_got_event; iv_fd_register(&this->fd); INIT_IV_AVL_TREE(&this->watches, __iv_inotify_watch_compare); return 0; } void iv_inotify_unregister(struct iv_inotify *this) { iv_fd_unregister(&this->fd); close(this->fd.fd); if (this->term != NULL) *this->term = NULL; } int iv_inotify_watch_register(struct iv_inotify_watch *w) { struct iv_inotify *inotify = w->inotify; w->wd = inotify_add_watch(inotify->fd.fd, w->pathname, w->mask); if (w->wd == -1) return -1; return iv_avl_tree_insert(&inotify->watches, &w->an); } void iv_inotify_watch_unregister(struct iv_inotify_watch *w) { struct iv_inotify *inotify = w->inotify; inotify_rm_watch(inotify->fd.fd, w->wd); iv_avl_tree_delete(&inotify->watches, &w->an); } ivykis-0.36.2/src/iv_main_posix.c000066400000000000000000000046611210744026200167240ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2009, 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include "iv_private.h" int iv_state_key_allocated; pthread_key_t iv_state_key; #ifdef HAVE_THREAD __thread struct iv_state *__st; #endif static void __iv_deinit(struct iv_state *st) { iv_tls_thread_deinit(st); iv_fd_deinit(st); iv_timer_deinit(st); pthread_setspecific(iv_state_key, NULL); #ifdef HAVE_THREAD __st = NULL; #endif free(st); } static void iv_state_destructor(void *data) { struct iv_state *st = data; pthread_setspecific(iv_state_key, st); __iv_deinit(st); } void iv_init(void) { struct iv_state *st; if (!iv_state_key_allocated) { if (pthread_key_create(&iv_state_key, iv_state_destructor)) iv_fatal("iv_init: failed to allocate TLS key"); iv_state_key_allocated = 1; } st = calloc(1, iv_tls_total_state_size()); pthread_setspecific(iv_state_key, st); #ifdef HAVE_THREAD __st = st; #endif st->numobjs = 0; iv_fd_init(st); iv_task_init(st); iv_timer_init(st); iv_tls_thread_init(st); } int iv_inited(void) { #ifndef HAVE_THREAD if (!iv_state_key_allocated) return 0; #endif return iv_get_state() != NULL; } void iv_quit(void) { struct iv_state *st = iv_get_state(); st->quit = 1; } void iv_main(void) { struct iv_state *st = iv_get_state(); st->quit = 0; while (1) { struct timespec to; iv_run_tasks(st); iv_run_timers(st); if (st->quit || !st->numobjs) break; if (iv_pending_tasks(st) || iv_get_soonest_timeout(st, &to)) { to.tv_sec = 0; to.tv_nsec = 0; } iv_fd_poll_and_run(st, &to); } } void iv_deinit(void) { struct iv_state *st = iv_get_state(); __iv_deinit(st); } ivykis-0.36.2/src/iv_main_win32.c000066400000000000000000000047441210744026200165260ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2009, 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include "iv_private.h" DWORD iv_state_index = -1; void iv_init(void) { struct iv_state *st; if (iv_state_index == -1) { iv_state_index = TlsAlloc(); if (iv_state_index == TLS_OUT_OF_INDEXES) iv_fatal("iv_init: failed to allocate TLS key"); } st = calloc(1, iv_tls_total_state_size()); TlsSetValue(iv_state_index, st); st->quit = 0; st->numobjs = 0; iv_handle_init(st); iv_task_init(st); iv_time_init(st); iv_timer_init(st); iv_tls_thread_init(st); } int iv_inited(void) { if (iv_state_index == -1) return 0; return iv_get_state() != NULL; } void iv_quit(void) { struct iv_state *st = iv_get_state(); st->quit = 1; } void iv_main(void) { struct iv_state *st = iv_get_state(); st->quit = 0; while (1) { struct timespec to; iv_run_tasks(st); iv_run_timers(st); if (st->quit || !st->numobjs) break; if (iv_pending_tasks(st) || iv_get_soonest_timeout(st, &to)) { to.tv_sec = 0; to.tv_nsec = 0; } iv_handle_poll_and_run(st, &to); } } static void __iv_deinit(struct iv_state *st) { iv_tls_thread_deinit(st); iv_handle_deinit(st); iv_timer_deinit(st); TlsSetValue(iv_state_index, NULL); free(st); } void iv_deinit(void) { struct iv_state *st = iv_get_state(); __iv_deinit(st); } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { if (iv_state_index == -1) return TRUE; if (fdwReason == DLL_PROCESS_DETACH || fdwReason == DLL_THREAD_DETACH) { struct iv_state *st; st = iv_get_state(); if (st != NULL) __iv_deinit(st); } if (fdwReason == DLL_PROCESS_DETACH) { TlsFree(iv_state_index); iv_state_index = -1; } return TRUE; } ivykis-0.36.2/src/iv_popen.c000066400000000000000000000105701210744026200156730ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include /* * This struct contains the child state that may need to persist * after iv_popen_request_close(). * * If parent == NULL, the corresponding popen request has been * closed, and signal_timer will be running to periodically kill * the child until it dies. */ struct iv_popen_running_child { struct iv_wait_interest wait; struct iv_popen_request *parent; struct iv_timer signal_timer; int num_kills; }; static void iv_popen_running_child_wait(void *_ch, int status, struct rusage *rusage) { struct iv_popen_running_child *ch = _ch; if (!WIFEXITED(status) && !WIFSIGNALED(status)) return; iv_wait_interest_unregister(&ch->wait); if (ch->parent != NULL) ch->parent->child = NULL; else iv_timer_unregister(&ch->signal_timer); free(ch); } struct iv_popen_spawn_info { struct iv_popen_request *this; int for_read; int data_pipe[2]; }; static void iv_popen_child(void *cookie) { struct iv_popen_spawn_info *info = cookie; int devnull; devnull = open("/dev/null", O_RDWR); if (devnull < 0) { iv_fatal("iv_popen_child: got error %d[%s] opening " "/dev/null", errno, strerror(errno)); } if (info->for_read) { dup2(devnull, 0); dup2(info->data_pipe[1], 1); dup2(devnull, 2); } else { dup2(info->data_pipe[0], 0); dup2(devnull, 1); dup2(devnull, 2); } close(info->data_pipe[0]); close(info->data_pipe[1]); close(devnull); execvp(info->this->file, info->this->argv); perror("execvp"); } int iv_popen_request_submit(struct iv_popen_request *this) { struct iv_popen_running_child *ch; struct iv_popen_spawn_info info; int ret; int fd; ch = malloc(sizeof(*ch)); if (ch == NULL) { fprintf(stderr, "iv_popen_request_submit: out of memory\n"); return -1; } info.this = this; if (!strcmp(this->type, "r")) { info.for_read = 1; } else if (!strcmp(this->type, "w")) { info.for_read = 0; } else { fprintf(stderr, "iv_popen_request_submit: invalid type\n"); free(ch); return -1; } if (pipe(info.data_pipe) < 0) { perror("pipe"); free(ch); return -1; } IV_WAIT_INTEREST_INIT(&ch->wait); ch->wait.cookie = ch; ch->wait.handler = iv_popen_running_child_wait; ch->parent = this; ret = iv_wait_interest_register_spawn(&ch->wait, iv_popen_child, &info); if (ret < 0) { perror("fork"); close(info.data_pipe[1]); close(info.data_pipe[0]); free(ch); return -1; } this->child = ch; if (info.for_read) { fd = info.data_pipe[0]; close(info.data_pipe[1]); } else { fd = info.data_pipe[1]; close(info.data_pipe[0]); } return fd; } #define MAX_SIGTERM_COUNT 5 #define SIGNAL_INTERVAL 5 static void iv_popen_running_child_timer(void *_ch) { struct iv_popen_running_child *ch = _ch; int signum; int ret; signum = (ch->num_kills++ < MAX_SIGTERM_COUNT) ? SIGTERM : SIGKILL; ret = iv_wait_interest_kill(&ch->wait, signum); if (ret < 0) { iv_wait_interest_unregister(&ch->wait); free(ch); return; } iv_validate_now(); ch->signal_timer.expires = iv_now; ch->signal_timer.expires.tv_sec += SIGNAL_INTERVAL; iv_timer_register(&ch->signal_timer); } void iv_popen_request_close(struct iv_popen_request *this) { struct iv_popen_running_child *ch = this->child; if (ch != NULL) { ch->parent = NULL; IV_TIMER_INIT(&ch->signal_timer); iv_validate_now(); ch->signal_timer.expires = iv_now; ch->signal_timer.handler = iv_popen_running_child_timer; ch->signal_timer.cookie = ch; iv_timer_register(&ch->signal_timer); ch->num_kills = 0; } } ivykis-0.36.2/src/iv_private.h000066400000000000000000000107431210744026200162330ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2009, 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "iv.h" #include "iv_avl.h" #include "iv_list.h" #include "config.h" /* * Per-thread state. */ struct iv_state { /* iv_main_{posix,win32}.c */ int quit; int numobjs; #ifndef _WIN32 /* iv_fd.c */ int numfds; struct iv_fd_ *handled_fd; #endif #ifdef _WIN32 /* iv_handle.c */ HANDLE wait; HANDLE thread_stop; struct iv_list_head handles; CRITICAL_SECTION active_handle_list_lock; struct iv_list_head active_with_handler; struct iv_list_head active_without_handler; struct iv_handle_ *handled_handle; #endif /* iv_task.c */ struct iv_list_head tasks; /* iv_timer.c */ struct timespec time; int time_valid; int num_timers; int rat_depth; struct ratnode *timer_root; #ifndef _WIN32 /* poll methods */ union { #ifdef HAVE_SYS_DEVPOLL_H struct { struct iv_avl_tree fds; int poll_fd; struct iv_list_head notify; } dev_poll; #endif #ifdef HAVE_EPOLL_CREATE struct { int epoll_fd; struct iv_list_head notify; } epoll; #endif #ifdef HAVE_KQUEUE struct { int kqueue_fd; struct iv_list_head notify; } kqueue; #endif struct { struct pollfd *pfds; struct iv_fd_ **fds; int num_regd_fds; } poll; #ifdef HAVE_PORT_CREATE struct { int port_fd; struct iv_list_head notify; } port; #endif } u; #endif }; #if !defined(_WIN32) && defined(HAVE_THREAD) extern __thread struct iv_state *__st; static inline struct iv_state *iv_get_state(void) { return __st; } #elif !defined(_WIN32) && !defined(HAVE_THREAD) #include extern pthread_key_t iv_state_key; static inline struct iv_state *iv_get_state(void) { return pthread_getspecific(iv_state_key); } #else extern DWORD iv_state_index; static inline struct iv_state *iv_get_state(void) { return TlsGetValue(iv_state_index); } #endif /* * Private versions of the task/timer structures, exposing their * internal state. The user data fields of these structures MUST * match the definitions in the public header file iv.h. */ struct iv_task_ { /* * User data. */ void *cookie; void (*handler)(void *); /* * Private data. */ struct iv_list_head list; }; struct iv_timer_ { /* * User data. */ struct timespec expires; void *cookie; void (*handler)(void *); /* * Private data. */ int index; }; /* * Misc internal stuff. */ #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) static inline void __iv_list_steal_elements(struct iv_list_head *oldh, struct iv_list_head *newh) { struct iv_list_head *first = oldh->next; struct iv_list_head *last = oldh->prev; last->next = newh; first->prev = newh; newh->next = oldh->next; newh->prev = oldh->prev; oldh->next = oldh; oldh->prev = oldh; } /* iv_fd.c */ void iv_fd_init(struct iv_state *st); void iv_fd_deinit(struct iv_state *st); void iv_fd_poll_and_run(struct iv_state *st, struct timespec *to); /* iv_handle.c */ void iv_handle_init(struct iv_state *st); void iv_handle_deinit(struct iv_state *st); void iv_handle_poll_and_run(struct iv_state *st, struct timespec *to); /* iv_task.c */ void iv_task_init(struct iv_state *st); int iv_pending_tasks(struct iv_state *st); void iv_run_tasks(struct iv_state *st); /* iv_time_{posix,win32}.c */ void iv_time_get(struct timespec *time); /* iv_time_win32.c */ void iv_time_init(struct iv_state *st); /* iv_timer.c */ void __iv_invalidate_now(struct iv_state *st); void iv_timer_init(struct iv_state *st); int iv_get_soonest_timeout(struct iv_state *st, struct timespec *to); void iv_run_timers(struct iv_state *st); void iv_timer_deinit(struct iv_state *st); /* iv_tls.c */ int iv_tls_total_state_size(void); void iv_tls_thread_init(struct iv_state *st); void iv_tls_thread_deinit(struct iv_state *st); ivykis-0.36.2/src/iv_signal.c000066400000000000000000000120351210744026200160250ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include "spinlock.h" static spinlock_t sig_interests_lock; static struct iv_avl_tree sig_interests; static sigset_t sig_mask_fork; static int iv_signal_compare(struct iv_avl_node *_a, struct iv_avl_node *_b) { struct iv_signal *a = iv_container_of(_a, struct iv_signal, an); struct iv_signal *b = iv_container_of(_b, struct iv_signal, an); if (a->signum < b->signum) return -1; if (a->signum > b->signum) return 1; if ((a->flags & IV_SIGNAL_FLAG_EXCLUSIVE) && !(b->flags & IV_SIGNAL_FLAG_EXCLUSIVE)) return -1; if (!(a->flags & IV_SIGNAL_FLAG_EXCLUSIVE) && (b->flags & IV_SIGNAL_FLAG_EXCLUSIVE)) return 1; if (a < b) return -1; if (a > b) return 1; return 0; } static void iv_signal_prepare(void) { sigset_t mask; spin_lock_sigmask(&sig_interests_lock, &mask); sig_mask_fork = mask; } static void iv_signal_parent(void) { sigset_t mask; mask = sig_mask_fork; spin_unlock_sigmask(&sig_interests_lock, &mask); } static void iv_signal_child(void) { struct sigaction sa; int last_signum; struct iv_avl_node *an; sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; last_signum = -1; iv_avl_tree_for_each (an, &sig_interests) { struct iv_signal *is; is = iv_container_of(an, struct iv_signal, an); if (is->signum != last_signum) { sigaction(is->signum, &sa, NULL); last_signum = is->signum; } } sig_interests.root = NULL; iv_signal_parent(); } static void iv_signal_init(void) __attribute__((constructor)); static void iv_signal_init(void) { spin_init(&sig_interests_lock); INIT_IV_AVL_TREE(&sig_interests, iv_signal_compare); pthread_atfork(iv_signal_prepare, iv_signal_parent, iv_signal_child); } static struct iv_avl_node *__iv_signal_find_first(int signum) { struct iv_avl_node *iter; struct iv_avl_node *best; for (iter = sig_interests.root, best = NULL; iter != NULL; ) { struct iv_signal *is; is = iv_container_of(iter, struct iv_signal, an); if (signum == is->signum) best = iter; if (signum <= is->signum) iter = iter->left; else iter = iter->right; } return best; } static void __iv_signal_do_wake(int signum) { struct iv_avl_node *an; an = __iv_signal_find_first(signum); while (an != NULL) { struct iv_signal *is; is = iv_container_of(an, struct iv_signal, an); if (is->signum != signum) break; is->active = 1; iv_event_raw_post(&is->ev); if (is->flags & IV_SIGNAL_FLAG_EXCLUSIVE) break; an = iv_avl_tree_next(an); } } static void iv_signal_handler(int signum) { spin_lock(&sig_interests_lock); __iv_signal_do_wake(signum); spin_unlock(&sig_interests_lock); } static void iv_signal_event(void *_this) { struct iv_signal *this = _this; sigset_t mask; spin_lock_sigmask(&sig_interests_lock, &mask); this->active = 0; spin_unlock_sigmask(&sig_interests_lock, &mask); this->handler(this->cookie); } int iv_signal_register(struct iv_signal *this) { sigset_t mask; IV_EVENT_RAW_INIT(&this->ev); this->ev.cookie = this; this->ev.handler = iv_signal_event; iv_event_raw_register(&this->ev); this->active = 0; spin_lock_sigmask(&sig_interests_lock, &mask); if (__iv_signal_find_first(this->signum) == NULL) { struct sigaction sa; sa.sa_handler = iv_signal_handler; sigfillset(&sa.sa_mask); #ifndef __QNX__ sa.sa_flags = SA_RESTART; #else sa.sa_flags = 0; #endif if (sigaction(this->signum, &sa, NULL) < 0) { iv_fatal("iv_signal_register: sigaction got " "error %d[%s]", errno, strerror(errno)); } } iv_avl_tree_insert(&sig_interests, &this->an); spin_unlock_sigmask(&sig_interests_lock, &mask); return 0; } void iv_signal_unregister(struct iv_signal *this) { sigset_t mask; spin_lock_sigmask(&sig_interests_lock, &mask); iv_avl_tree_delete(&sig_interests, &this->an); if (__iv_signal_find_first(this->signum) == NULL) { struct sigaction sa; sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(this->signum, &sa, NULL); } else if ((this->flags & IV_SIGNAL_FLAG_EXCLUSIVE) && this->active) { __iv_signal_do_wake(this->signum); } spin_unlock_sigmask(&sig_interests_lock, &mask); iv_event_raw_unregister(&this->ev); } ivykis-0.36.2/src/iv_task.c000066400000000000000000000042031210744026200155100ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2009 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include "iv_private.h" void iv_task_init(struct iv_state *st) { INIT_IV_LIST_HEAD(&st->tasks); } int iv_pending_tasks(struct iv_state *st) { return !iv_list_empty(&st->tasks); } void iv_run_tasks(struct iv_state *st) { struct iv_list_head tasks; __iv_list_steal_elements(&st->tasks, &tasks); while (!iv_list_empty(&tasks)) { struct iv_task_ *t; t = iv_list_entry(tasks.next, struct iv_task_, list); iv_list_del_init(&t->list); st->numobjs--; t->handler(t->cookie); } } void IV_TASK_INIT(struct iv_task *_t) { struct iv_task_ *t = (struct iv_task_ *)_t; INIT_IV_LIST_HEAD(&t->list); } void iv_task_register(struct iv_task *_t) { struct iv_state *st = iv_get_state(); struct iv_task_ *t = (struct iv_task_ *)_t; if (!iv_list_empty(&t->list)) iv_fatal("iv_task_register: called with task still on a list"); st->numobjs++; iv_list_add_tail(&t->list, &st->tasks); } void iv_task_unregister(struct iv_task *_t) { struct iv_state *st = iv_get_state(); struct iv_task_ *t = (struct iv_task_ *)_t; if (iv_list_empty(&t->list)) iv_fatal("iv_task_unregister: called with task not on a list"); st->numobjs--; iv_list_del_init(&t->list); } int iv_task_registered(struct iv_task *_t) { struct iv_task_ *t = (struct iv_task_ *)_t; return !iv_list_empty(&t->list); } ivykis-0.36.2/src/iv_thread_posix.c000066400000000000000000000131071210744026200172420ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include "config.h" /* thread ID ****************************************************************/ #ifdef HAVE_PROCESS_H #include #endif #ifdef HAVE_SYS_SYSCALL_H #include #endif #ifdef HAVE_SYS_THR_H /* Older FreeBSDs (6.1) don't include sys/ucontext.h in sys/thr.h. */ #include #include #endif #ifdef HAVE_THREAD_H #include #endif static unsigned long get_thread_id(void) { unsigned long thread_id; #if defined(__NR_gettid) thread_id = syscall(__NR_gettid); #elif defined(HAVE_GETTID) && defined(HAVE_PROCESS_H) thread_id = gettid(); #elif defined(HAVE_LWP_GETTID) thread_id = lwp_gettid(); #elif defined(HAVE_THR_SELF) && defined(HAVE_SYS_THR_H) long thr; thr_self(&thr); thread_id = (unsigned long)thr; #elif defined(HAVE_THR_SELF) && defined(HAVE_THREAD_H) thread_id = thr_self(); #else #warning using pthread_self for get_thread_id thread_id = (unsigned long)pthread_self(); #endif return thread_id; } /* data structures and global data ******************************************/ struct iv_thread { struct iv_list_head list; pthread_t thread_id; struct iv_event dead; char *name; unsigned long tid; void (*start_routine)(void *); void *arg; }; static int iv_thread_debug; /* tls **********************************************************************/ struct iv_thread_thr_info { struct iv_list_head child_threads; }; static void iv_thread_tls_init_thread(void *_tinfo) { struct iv_thread_thr_info *tinfo = _tinfo; INIT_IV_LIST_HEAD(&tinfo->child_threads); } static void iv_thread_tls_deinit_thread(void *_tinfo) { struct iv_thread_thr_info *tinfo = _tinfo; struct iv_list_head *ilh; iv_list_for_each (ilh, &tinfo->child_threads) { struct iv_thread *thr; thr = iv_list_entry(ilh, struct iv_thread, list); pthread_detach(thr->thread_id); } } static struct iv_tls_user iv_thread_tls_user = { .sizeof_state = sizeof(struct iv_thread_thr_info), .init_thread = iv_thread_tls_init_thread, .deinit_thread = iv_thread_tls_deinit_thread, }; static void iv_thread_tls_init(void) __attribute__((constructor)); static void iv_thread_tls_init(void) { iv_tls_user_register(&iv_thread_tls_user); } /* callee thread ************************************************************/ static void iv_thread_cleanup_handler(void *_thr) { struct iv_thread *thr = _thr; if (iv_thread_debug) fprintf(stderr, "iv_thread: [%s] was canceled\n", thr->name); iv_event_post(&thr->dead); } static void *iv_thread_handler(void *_thr) { struct iv_thread *thr = _thr; thr->tid = get_thread_id(); pthread_cleanup_push(iv_thread_cleanup_handler, thr); thr->start_routine(thr->arg); pthread_cleanup_pop(0); if (iv_thread_debug) fprintf(stderr, "iv_thread: [%s] terminating normally\n", thr->name); iv_event_post(&thr->dead); return NULL; } /* calling thread ***********************************************************/ static void iv_thread_died(void *_thr) { struct iv_thread *thr = _thr; pthread_join(thr->thread_id, NULL); if (iv_thread_debug) fprintf(stderr, "iv_thread: [%s] joined\n", thr->name); iv_list_del(&thr->list); iv_event_unregister(&thr->dead); free(thr->name); free(thr); } int iv_thread_create(char *name, void (*start_routine)(void *), void *arg) { struct iv_thread_thr_info *tinfo = iv_tls_user_ptr(&iv_thread_tls_user); struct iv_thread *thr; int ret; thr = malloc(sizeof(*thr)); if (thr == NULL) return -1; IV_EVENT_INIT(&thr->dead); thr->dead.cookie = thr; thr->dead.handler = iv_thread_died; iv_event_register(&thr->dead); thr->name = strdup(name); thr->tid = 0; thr->start_routine = start_routine; thr->arg = arg; ret = pthread_create(&thr->thread_id, NULL, iv_thread_handler, thr); if (ret) goto out; iv_list_add_tail(&thr->list, &tinfo->child_threads); if (iv_thread_debug) fprintf(stderr, "iv_thread: [%s] started\n", name); return 0; out: iv_event_unregister(&thr->dead); free(thr->name); free(thr); if (iv_thread_debug) { fprintf(stderr, "iv_thread: pthread_create for [%s] " "failed with error %d[%s]\n", name, ret, strerror(ret)); } return -1; } void iv_thread_set_debug_state(int state) { iv_thread_debug = !!state; } unsigned long iv_thread_get_id(void) { return get_thread_id(); } void iv_thread_list_children(void) { struct iv_thread_thr_info *tinfo = iv_tls_user_ptr(&iv_thread_tls_user); struct iv_list_head *ilh; fprintf(stderr, "tid\tname\n"); fprintf(stderr, "%lu\tself\n", get_thread_id()); iv_list_for_each (ilh, &tinfo->child_threads) { struct iv_thread *thr; thr = iv_list_entry(ilh, struct iv_thread, list); fprintf(stderr, "%lu\t%s\n", thr->tid, thr->name); } } ivykis-0.36.2/src/iv_thread_win32.c000066400000000000000000000103601210744026200170400ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010, 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include /* data structures and global data ******************************************/ struct iv_thread { struct iv_list_head list; DWORD thread_id; struct iv_handle thread_handle; char *name; void (*start_routine)(void *); void *arg; }; static int iv_thread_debug; /* tls **********************************************************************/ struct iv_thread_thr_info { struct iv_list_head child_threads; }; static void iv_thread_tls_init_thread(void *_tinfo) { struct iv_thread_thr_info *tinfo = _tinfo; INIT_IV_LIST_HEAD(&tinfo->child_threads); } static void iv_thread_tls_deinit_thread(void *_tinfo) { struct iv_thread_thr_info *tinfo = _tinfo; struct iv_list_head *ilh; iv_list_for_each (ilh, &tinfo->child_threads) { struct iv_thread *thr; thr = iv_list_entry(ilh, struct iv_thread, list); iv_handle_unregister(&thr->thread_handle); CloseHandle(thr->thread_handle.handle); thr->thread_handle.handle = INVALID_HANDLE_VALUE; } } static struct iv_tls_user iv_thread_tls_user = { .sizeof_state = sizeof(struct iv_thread_thr_info), .init_thread = iv_thread_tls_init_thread, .deinit_thread = iv_thread_tls_deinit_thread, }; static void iv_thread_tls_init(void) __attribute__((constructor)); static void iv_thread_tls_init(void) { iv_tls_user_register(&iv_thread_tls_user); } /* callee thread ************************************************************/ static DWORD WINAPI iv_thread_handler(void *_thr) { struct iv_thread *thr = _thr; thr->start_routine(thr->arg); return 0; } /* calling thread ***********************************************************/ static void iv_thread_died(void *_thr) { struct iv_thread *thr = _thr; iv_handle_unregister(&thr->thread_handle); CloseHandle(thr->thread_handle.handle); if (iv_thread_debug) fprintf(stderr, "iv_thread: [%s] terminated\n", thr->name); iv_list_del(&thr->list); free(thr->name); free(thr); } int iv_thread_create(char *name, void (*start_routine)(void *), void *arg) { struct iv_thread_thr_info *tinfo = iv_tls_user_ptr(&iv_thread_tls_user); struct iv_thread *thr; HANDLE h; thr = malloc(sizeof(*thr)); if (thr == NULL) return -1; IV_HANDLE_INIT(&thr->thread_handle); thr->thread_handle.cookie = thr; thr->thread_handle.handler = iv_thread_died; thr->name = strdup(name); thr->start_routine = start_routine; thr->arg = arg; h = CreateThread(NULL, 0, iv_thread_handler, thr, 0, &thr->thread_id); if (h == NULL) goto out; thr->thread_handle.handle = h; iv_handle_register(&thr->thread_handle); iv_list_add_tail(&thr->list, &tinfo->child_threads); if (iv_thread_debug) fprintf(stderr, "iv_thread: [%s] started\n", name); return 0; out: free(thr->name); free(thr); if (iv_thread_debug) fprintf(stderr, "iv_thread: [%s] failed to start\n", name); return -1; } void iv_thread_set_debug_state(int state) { iv_thread_debug = !!state; } unsigned long iv_thread_get_id(void) { return GetCurrentThreadId(); } void iv_thread_list_children(void) { struct iv_thread_thr_info *tinfo = iv_tls_user_ptr(&iv_thread_tls_user); struct iv_list_head *ilh; fprintf(stderr, "tid\tname\n"); fprintf(stderr, "%d\tself\n", (int)GetCurrentThreadId()); iv_list_for_each (ilh, &tinfo->child_threads) { struct iv_thread *thr; thr = iv_list_entry(ilh, struct iv_thread, list); fprintf(stderr, "%d\t%s\n", (int)thr->thread_id, thr->name); } } ivykis-0.36.2/src/iv_time_posix.c000066400000000000000000000027611210744026200167350ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2009, 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include "iv_private.h" #ifdef HAVE_CLOCK_GETTIME static int clock_source; #endif void iv_time_get(struct timespec *time) { struct timeval tv; #if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC) if (clock_source < 1) { if (clock_gettime(CLOCK_MONOTONIC, time) >= 0) return; clock_source = 1; } #endif #if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_REALTIME) if (clock_source < 2) { if (clock_gettime(CLOCK_REALTIME, time) >= 0) return; clock_source = 2; } #endif gettimeofday(&tv, NULL); time->tv_sec = tv.tv_sec; time->tv_nsec = 1000L * tv.tv_usec; } ivykis-0.36.2/src/iv_time_win32.c000066400000000000000000000033701210744026200165320ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include "iv_private.h" static int method; static LONGLONG freq; static UINT32 last_sec; void iv_time_init(struct iv_state *st) { if (!method) { LARGE_INTEGER _freq; if (QueryPerformanceFrequency(&_freq)) { method = 1; freq = _freq.QuadPart; } else { method = 2; } } } void iv_time_get(struct timespec *time) { UINT32 local_last_sec; UINT32 msec; if (method == 1) { LARGE_INTEGER _cnt; if (QueryPerformanceCounter(&_cnt)) { LONGLONG cnt = _cnt.QuadPart; time->tv_sec = cnt / freq; time->tv_nsec = (1000000000ULL * (cnt % freq)) / freq; return; } method = 2; } local_last_sec = last_sec; msec = GetTickCount() - 1000 * local_last_sec; if (msec >= 1000) { local_last_sec += msec / 1000; msec %= 1000; last_sec = local_last_sec; } time->tv_sec = local_last_sec; time->tv_nsec = 1000000 * msec; } ivykis-0.36.2/src/iv_timer.c000066400000000000000000000155511210744026200156760ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2009, 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include "iv_private.h" /* time handling ************************************************************/ void __iv_invalidate_now(struct iv_state *st) { st->time_valid = 0; } void iv_invalidate_now(void) { struct iv_state *st = iv_get_state(); __iv_invalidate_now(st); } void iv_validate_now(void) { struct iv_state *st = iv_get_state(); if (!st->time_valid) { st->time_valid = 1; iv_time_get(&st->time); } } struct timespec *__iv_now_location(void) { struct iv_state *st = iv_get_state(); return &st->time; } /* internal use *************************************************************/ #define SPLIT_BITS (8) #define SPLIT_NODES (1 << SPLIT_BITS) struct ratnode { void *child[SPLIT_NODES]; }; static struct ratnode *iv_timer_allocate_ratnode(void) { struct ratnode *node; node = calloc(1, sizeof(struct ratnode)); if (node == NULL) iv_fatal("iv_timer_allocate_ratnode: out of memory"); return node; } void iv_timer_init(struct iv_state *st) { st->rat_depth = 0; st->timer_root = iv_timer_allocate_ratnode(); } static struct iv_timer_ **iv_timer_get_node(struct iv_state *st, int index) { struct ratnode *r; int i; if (index >> ((st->rat_depth + 1) * SPLIT_BITS) != 0) { st->rat_depth++; r = iv_timer_allocate_ratnode(); r->child[0] = st->timer_root; st->timer_root = r; } r = st->timer_root; for (i = st->rat_depth; i > 0; i--) { int bits; bits = (index >> (i * SPLIT_BITS)) & (SPLIT_NODES - 1); if (r->child[bits] == NULL) r->child[bits] = iv_timer_allocate_ratnode(); r = r->child[bits]; } return (struct iv_timer_ **)(r->child + (index & (SPLIT_NODES - 1))); } int iv_get_soonest_timeout(struct iv_state *st, struct timespec *to) { if (st->num_timers) { struct iv_timer_ *t = *iv_timer_get_node(st, 1); iv_validate_now(); to->tv_sec = t->expires.tv_sec - st->time.tv_sec; to->tv_nsec = t->expires.tv_nsec - st->time.tv_nsec; if (to->tv_nsec < 0) { to->tv_sec--; to->tv_nsec += 1000000000; } return !!(to->tv_sec < 0 || (to->tv_sec == 0 && to->tv_nsec == 0)); } to->tv_sec = 3600; to->tv_nsec = 0; return 0; } static inline int timespec_gt(struct timespec *a, struct timespec *b) { return !!(a->tv_sec > b->tv_sec || (a->tv_sec == b->tv_sec && a->tv_nsec > b->tv_nsec)); } void iv_run_timers(struct iv_state *st) { while (st->num_timers) { struct iv_timer_ *t = *iv_timer_get_node(st, 1); if (!st->time_valid) { st->time_valid = 1; iv_time_get(&st->time); } if (timespec_gt(&t->expires, &st->time)) break; iv_timer_unregister((struct iv_timer *)t); t->handler(t->cookie); } } static void free_ratnode(struct ratnode *node, int depth) { if (depth) { int i; for (i = 0; i < SPLIT_NODES; i++) { if (node->child[i] == NULL) break; free_ratnode(node->child[i], depth - 1); } } free(node); } void iv_timer_deinit(struct iv_state *st) { free_ratnode(st->timer_root, st->rat_depth); st->timer_root = NULL; } static void iv_timer_radix_tree_remove_level(struct iv_state *st) { struct ratnode *root; int i; st->rat_depth--; root = st->timer_root; for (i = 1; i < SPLIT_NODES; i++) { if (root->child[i] == NULL) break; free_ratnode(root->child[i], st->rat_depth); } st->timer_root = root->child[0]; free(root); } /* public use ***************************************************************/ void IV_TIMER_INIT(struct iv_timer *_t) { struct iv_timer_ *t = (struct iv_timer_ *)_t; t->index = -1; } static inline int timer_ptr_gt(struct iv_timer_ *a, struct iv_timer_ *b) { return timespec_gt(&a->expires, &b->expires); } static void pull_up(struct iv_state *st, int index, struct iv_timer_ **i) { while (index != 1) { struct iv_timer_ *et; int parent; struct iv_timer_ **p; parent = index / 2; p = iv_timer_get_node(st, parent); if (!timer_ptr_gt(*p, *i)) break; et = *i; *i = *p; *p = et; (*i)->index = index; (*p)->index = parent; index = parent; i = p; } } void iv_timer_register(struct iv_timer *_t) { struct iv_state *st = iv_get_state(); struct iv_timer_ *t = (struct iv_timer_ *)_t; struct iv_timer_ **p; int index; if (t->index != -1) { iv_fatal("iv_timer_register: called with timer still " "on the heap"); } st->numobjs++; index = ++st->num_timers; p = iv_timer_get_node(st, index); *p = t; t->index = index; pull_up(st, index, p); } static void push_down(struct iv_state *st, int index, struct iv_timer_ **i) { while (1) { struct iv_timer_ *et; struct iv_timer_ **imin; int index_min; index_min = index; imin = i; if (2 * index <= st->num_timers) { struct iv_timer_ **p; p = iv_timer_get_node(st, 2 * index); if (timer_ptr_gt(*imin, p[0])) { index_min = 2 * index; imin = p; } if (p[1] && timer_ptr_gt(*imin, p[1])) { index_min = 2 * index + 1; imin = p + 1; } } if (index == index_min) break; et = *i; *i = *imin; *imin = et; (*i)->index = index; (*imin)->index = index_min; index = index_min; i = imin; } } void iv_timer_unregister(struct iv_timer *_t) { struct iv_state *st = iv_get_state(); struct iv_timer_ *t = (struct iv_timer_ *)_t; struct iv_timer_ **m; struct iv_timer_ **p; if (t->index == -1) { iv_fatal("iv_timer_unregister: called with timer not " "on the heap"); } if (t->index > st->num_timers) { iv_fatal("iv_timer_unregister: timer index %d > %d", t->index, st->num_timers); } p = iv_timer_get_node(st, t->index); if (*p != t) { iv_fatal("iv_timer_unregister: unregistered timer " "index belonging to other timer"); } st->numobjs--; m = iv_timer_get_node(st, st->num_timers); *p = *m; (*p)->index = t->index; *m = NULL; if (st->rat_depth > 0 && st->num_timers == (1 << (st->rat_depth * SPLIT_BITS))) iv_timer_radix_tree_remove_level(st); st->num_timers--; if (p != m) { pull_up(st, (*p)->index, p); push_down(st, (*p)->index, p); } t->index = -1; } int iv_timer_registered(struct iv_timer *_t) { struct iv_timer_ *t = (struct iv_timer_ *)_t; return !(t->index == -1); } ivykis-0.36.2/src/iv_tls.c000066400000000000000000000043571210744026200153620ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2011 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include "iv_private.h" static int inited; static int last_offset = (sizeof(struct iv_state) + 15) & ~15; static struct iv_list_head iv_tls_users = IV_LIST_HEAD_INIT(iv_tls_users); void iv_tls_user_register(struct iv_tls_user *itu) { if (inited) iv_fatal("iv_tls_user_register: called after iv_init"); itu->state_offset = last_offset; last_offset = (last_offset + itu->sizeof_state + 15) & ~15; iv_list_add_tail(&itu->list, &iv_tls_users); } int iv_tls_total_state_size(void) { return last_offset; } void iv_tls_thread_init(struct iv_state *st) { struct iv_list_head *ilh; inited = 1; iv_list_for_each (ilh, &iv_tls_users) { struct iv_tls_user *itu; itu = iv_container_of(ilh, struct iv_tls_user, list); if (itu->init_thread != NULL) itu->init_thread(((void *)st) + itu->state_offset); } } void iv_tls_thread_deinit(struct iv_state *st) { struct iv_list_head *ilh; iv_list_for_each (ilh, &iv_tls_users) { struct iv_tls_user *itu; itu = iv_container_of(ilh, struct iv_tls_user, list); if (itu->deinit_thread != NULL) itu->deinit_thread(((void *)st) + itu->state_offset); } } void *iv_tls_user_ptr(struct iv_tls_user *itu) { struct iv_state *st = iv_get_state(); if (itu->state_offset == 0) iv_fatal("iv_tls_user_ptr: called on unregistered iv_tls_user"); if (st != NULL) return ((void *)st) + itu->state_offset; return NULL; } ivykis-0.36.2/src/iv_wait.c000066400000000000000000000172321210744026200155200ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include "iv_private.h" #include "config.h" #ifndef WCONTINUED #define WCONTINUED 0 #define WIFCONTINUED(x) 0 #endif #define IV_WAIT_STATUS_DEAD 1 struct wait_event { struct iv_list_head list; int status; #ifdef HAVE_WAIT4 struct rusage rusage; #endif }; static int iv_wait_interest_compare(struct iv_avl_node *_a, struct iv_avl_node *_b) { struct iv_wait_interest *a; struct iv_wait_interest *b; a = iv_container_of(_a, struct iv_wait_interest, avl_node); b = iv_container_of(_b, struct iv_wait_interest, avl_node); if (a->pid < b->pid) return -1; if (a->pid > b->pid) return 1; return 0; } static pthread_mutex_t iv_wait_lock; static struct iv_avl_tree iv_wait_interests = IV_AVL_TREE_INIT(iv_wait_interest_compare); static struct iv_wait_interest *__iv_wait_interest_find(int pid) { struct iv_avl_node *an; an = iv_wait_interests.root; while (an != NULL) { struct iv_wait_interest *p; p = iv_container_of(an, struct iv_wait_interest, avl_node); if (pid == p->pid) return p; if (pid < p->pid) an = an->left; else an = an->right; } return NULL; } static int iv_wait_status_dead(int status) { /* * On FreeBSD, WIFCONTINUED(status) => WIFSIGNALED(status). */ if (WIFSIGNALED(status) && !WIFCONTINUED(status)) return 1; if (WIFEXITED(status)) return 1; return 0; } static void iv_wait_got_sigchld(void *_dummy) { pthread_mutex_lock(&iv_wait_lock); while (1) { pid_t pid; int status; struct wait_event *we; struct iv_wait_interest *p; #ifdef HAVE_WAIT4 struct rusage rusage; #ifdef __digital__ union wait w; pid = wait4(-1, &w, WNOHANG | WUNTRACED | WCONTINUED, &rusage); status = w.w_status; #else pid = wait4(-1, &status, WNOHANG | WUNTRACED | WCONTINUED, &rusage); #endif if (pid <= 0) { if (pid < 0 && errno != ECHILD) perror("wait4"); break; } #else pid = waitpid(-1, &status, WNOHANG | WUNTRACED | WCONTINUED); if (pid <= 0) { if (pid < 0 && errno != ECHILD) perror("waitpid"); break; } #endif we = malloc(sizeof(*we)); if (we == NULL) iv_fatal("iv_wait_got_sigchld: out of memory"); we->status = status; #ifdef HAVE_WAIT4 we->rusage = rusage; #endif p = __iv_wait_interest_find(pid); if (p != NULL) { iv_list_add_tail(&we->list, &p->events); iv_event_post(&p->ev); } else { free(we); } /* * If this pid is now dead, avoid queueing subsequent * process status change events to this interest, as the * pid might be reused between us queueing this event to * the interest and the interest being unregistered, * and events for the new user of this pid would then end * up at the wrong interest. */ if (iv_wait_status_dead(status)) { iv_avl_tree_delete(&iv_wait_interests, &p->avl_node); p->flags = IV_WAIT_STATUS_DEAD; } } pthread_mutex_unlock(&iv_wait_lock); } struct iv_wait_thr_info { int wait_count; struct iv_signal sigchld_interest; struct iv_wait_interest *handled_wait_interest; }; static void iv_wait_tls_init_thread(void *_tinfo) { struct iv_wait_thr_info *tinfo = _tinfo; tinfo->wait_count = 0; IV_SIGNAL_INIT(&tinfo->sigchld_interest); tinfo->sigchld_interest.signum = SIGCHLD; tinfo->sigchld_interest.flags = IV_SIGNAL_FLAG_EXCLUSIVE; tinfo->sigchld_interest.handler = iv_wait_got_sigchld; tinfo->handled_wait_interest = NULL; } static struct iv_tls_user iv_wait_tls_user = { .sizeof_state = sizeof(struct iv_wait_thr_info), .init_thread = iv_wait_tls_init_thread, }; static void iv_wait_tls_init(void) __attribute__((constructor)); static void iv_wait_tls_init(void) { pthread_mutex_init(&iv_wait_lock, NULL); iv_tls_user_register(&iv_wait_tls_user); } static void iv_wait_completion(void *_this) { struct iv_wait_thr_info *tinfo = iv_tls_user_ptr(&iv_wait_tls_user); struct iv_wait_interest *this = _this; struct iv_list_head events; pthread_mutex_lock(&iv_wait_lock); __iv_list_steal_elements(&this->events, &events); pthread_mutex_unlock(&iv_wait_lock); tinfo->handled_wait_interest = this; while (!iv_list_empty(&events)) { struct wait_event *we; we = iv_container_of(events.next, struct wait_event, list); iv_list_del(&we->list); if (tinfo->handled_wait_interest != NULL) { #ifdef HAVE_WAIT4 this->handler(this->cookie, we->status, &we->rusage); #else this->handler(this->cookie, we->status, NULL); #endif } free(we); } tinfo->handled_wait_interest = NULL; } static void __iv_wait_interest_register(struct iv_wait_thr_info *tinfo, struct iv_wait_interest *this) { if (!tinfo->wait_count++) iv_signal_register(&tinfo->sigchld_interest); IV_EVENT_INIT(&this->ev); this->ev.handler = iv_wait_completion; this->ev.cookie = this; iv_event_register(&this->ev); INIT_IV_LIST_HEAD(&this->events); this->dummy = NULL; this->flags = 0; } void iv_wait_interest_register(struct iv_wait_interest *this) { struct iv_wait_thr_info *tinfo = iv_tls_user_ptr(&iv_wait_tls_user); __iv_wait_interest_register(tinfo, this); pthread_mutex_lock(&iv_wait_lock); iv_avl_tree_insert(&iv_wait_interests, &this->avl_node); pthread_mutex_unlock(&iv_wait_lock); } static void __iv_wait_interest_unregister(struct iv_wait_thr_info *tinfo, struct iv_wait_interest *this) { iv_event_unregister(&this->ev); while (!iv_list_empty(&this->events)) { struct wait_event *we; we = iv_container_of(this->events.next, struct wait_event, list); iv_list_del(&we->list); free(we); } if (tinfo->handled_wait_interest == this) tinfo->handled_wait_interest = NULL; if (!--tinfo->wait_count) iv_signal_unregister(&tinfo->sigchld_interest); } int iv_wait_interest_register_spawn(struct iv_wait_interest *this, void (*fn)(void *cookie), void *cookie) { struct iv_wait_thr_info *tinfo = iv_tls_user_ptr(&iv_wait_tls_user); pid_t pid; __iv_wait_interest_register(tinfo, this); pthread_mutex_lock(&iv_wait_lock); pid = fork(); if (pid < 0) { pthread_mutex_unlock(&iv_wait_lock); __iv_wait_interest_unregister(tinfo, this); return pid; } if (pid == 0) { fn(cookie); exit(1); } else { this->pid = pid; iv_avl_tree_insert(&iv_wait_interests, &this->avl_node); } pthread_mutex_unlock(&iv_wait_lock); return 0; } void iv_wait_interest_unregister(struct iv_wait_interest *this) { struct iv_wait_thr_info *tinfo = iv_tls_user_ptr(&iv_wait_tls_user); pthread_mutex_lock(&iv_wait_lock); if (!(this->flags & IV_WAIT_STATUS_DEAD)) iv_avl_tree_delete(&iv_wait_interests, &this->avl_node); pthread_mutex_unlock(&iv_wait_lock); __iv_wait_interest_unregister(tinfo, this); } int iv_wait_interest_kill(struct iv_wait_interest *this, int sig) { int ret; pthread_mutex_lock(&iv_wait_lock); if (!(this->flags & IV_WAIT_STATUS_DEAD)) ret = kill(this->pid, sig); else ret = -ESRCH; pthread_mutex_unlock(&iv_wait_lock); return ret; } ivykis-0.36.2/src/iv_work.c000066400000000000000000000226101210744026200155320ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010, 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include "iv_private.h" #include "mutex.h" /* data structures **********************************************************/ struct work_pool_priv { __mutex_t lock; struct iv_event ev; int shutting_down; int started_threads; struct iv_list_head idle_threads; void *cookie; void (*thread_start)(void *cookie); void (*thread_stop)(void *cookie); uint32_t seq_head; uint32_t seq_tail; struct iv_list_head work_items; struct iv_list_head work_done; }; struct work_pool_thread { struct work_pool_priv *pool; struct iv_list_head list; int kicked; struct iv_event kick; struct iv_task work_task; struct iv_timer idle_timer; }; /* worker thread ************************************************************/ static void iv_work_thread_got_event(void *_thr) { struct work_pool_thread *thr = _thr; struct work_pool_priv *pool = thr->pool; mutex_lock(&pool->lock); thr->kicked = 0; if (!iv_list_empty(&thr->list)) { iv_list_del_init(&thr->list); iv_task_register(&thr->work_task); iv_timer_unregister(&thr->idle_timer); } mutex_unlock(&pool->lock); } static void __iv_work_thread_die(struct work_pool_thread *thr) { struct work_pool_priv *pool = thr->pool; if (thr->kicked) iv_fatal("__iv_work_thread_die: called on kicked thread"); if (!iv_list_empty(&thr->list)) iv_fatal("__iv_work_thread_die: thread still on list"); iv_event_unregister(&thr->kick); free(thr); pool->started_threads--; if (pool->thread_stop != NULL) pool->thread_stop(pool->cookie); if (pool->shutting_down && !pool->started_threads) iv_event_post(&pool->ev); } static void iv_work_thread_do_work(void *_thr) { struct work_pool_thread *thr = _thr; struct work_pool_priv *pool = thr->pool; uint32_t last_seq; mutex_lock(&pool->lock); last_seq = pool->seq_tail; while ((int32_t)(last_seq - pool->seq_head) > 0) { struct iv_work_item *work; pool->seq_head++; work = iv_container_of(pool->work_items.next, struct iv_work_item, list); iv_list_del(&work->list); mutex_unlock(&pool->lock); work->work(work->cookie); iv_invalidate_now(); mutex_lock(&pool->lock); if (iv_list_empty(&pool->work_done)) iv_event_post(&pool->ev); iv_list_add_tail(&work->list, &pool->work_done); } if (pool->seq_head == pool->seq_tail) { if (!pool->shutting_down) { iv_list_add(&thr->list, &pool->idle_threads); iv_validate_now(); thr->idle_timer.expires = iv_now; thr->idle_timer.expires.tv_sec += 10; iv_timer_register(&thr->idle_timer); } else { __iv_work_thread_die(thr); } } else { /* * If we're already at the maximum number of pool * threads, and none of those threads were idle when * more work arrived, then there may have been no * kick sent for the new work item(s) (and no new * pool thread started either), so if we're leaving * with work items still pending, make sure we get * called again, so that we don't deadlock. */ iv_task_register(&thr->work_task); } mutex_unlock(&pool->lock); } static void iv_work_thread_idle_timeout(void *_thr) { struct work_pool_thread *thr = _thr; struct work_pool_priv *pool = thr->pool; mutex_lock(&pool->lock); if (thr->kicked) { thr->idle_timer.expires = iv_now; thr->idle_timer.expires.tv_sec += 10; iv_timer_register(&thr->idle_timer); } else { iv_list_del_init(&thr->list); __iv_work_thread_die(thr); } mutex_unlock(&pool->lock); } static void iv_work_thread(void *_thr) { struct work_pool_thread *thr = _thr; struct work_pool_priv *pool = thr->pool; iv_init(); INIT_IV_LIST_HEAD(&thr->list); thr->kicked = 0; IV_EVENT_INIT(&thr->kick); thr->kick.cookie = thr; thr->kick.handler = iv_work_thread_got_event; iv_event_register(&thr->kick); IV_TASK_INIT(&thr->work_task); thr->work_task.cookie = thr; thr->work_task.handler = iv_work_thread_do_work; iv_task_register(&thr->work_task); IV_TIMER_INIT(&thr->idle_timer); thr->idle_timer.cookie = thr; thr->idle_timer.handler = iv_work_thread_idle_timeout; if (pool->thread_start != NULL) pool->thread_start(pool->cookie); iv_main(); iv_deinit(); } /* main thread **************************************************************/ static void iv_work_event(void *_pool) { struct work_pool_priv *pool = _pool; struct iv_list_head items; mutex_lock(&pool->lock); __iv_list_steal_elements(&pool->work_done, &items); mutex_unlock(&pool->lock); while (!iv_list_empty(&items)) { struct iv_work_item *work; work = iv_container_of(items.next, struct iv_work_item, list); iv_list_del(&work->list); work->completion(work->cookie); } if (pool->shutting_down) { mutex_lock(&pool->lock); if (!pool->started_threads && iv_list_empty(&pool->work_done)) { mutex_unlock(&pool->lock); mutex_destroy(&pool->lock); iv_event_unregister(&pool->ev); free(pool); return; } mutex_unlock(&pool->lock); } } int iv_work_pool_create(struct iv_work_pool *this) { struct work_pool_priv *pool; int ret; pool = malloc(sizeof(*pool)); if (pool == NULL) return -1; ret = mutex_init(&pool->lock); if (ret) { free(pool); return -1; } IV_EVENT_INIT(&pool->ev); pool->ev.cookie = pool; pool->ev.handler = iv_work_event; iv_event_register(&pool->ev); pool->shutting_down = 0; pool->started_threads = 0; INIT_IV_LIST_HEAD(&pool->idle_threads); pool->cookie = this->cookie; pool->thread_start = this->thread_start; pool->thread_stop = this->thread_stop; pool->seq_head = 0; pool->seq_tail = 0; INIT_IV_LIST_HEAD(&pool->work_items); INIT_IV_LIST_HEAD(&pool->work_done); this->priv = pool; return 0; } void iv_work_pool_put(struct iv_work_pool *this) { struct work_pool_priv *pool = this->priv; struct iv_list_head *ilh; mutex_lock(&pool->lock); this->priv = NULL; pool->shutting_down = 1; if (!pool->started_threads) { mutex_unlock(&pool->lock); iv_event_post(&pool->ev); return; } iv_list_for_each (ilh, &pool->idle_threads) { struct work_pool_thread *thr; thr = iv_container_of(ilh, struct work_pool_thread, list); iv_event_post(&thr->kick); } mutex_unlock(&pool->lock); } static int iv_work_start_thread(struct work_pool_priv *pool) { struct work_pool_thread *thr; char name[512]; int ret; thr = malloc(sizeof(*thr)); if (thr == NULL) return -1; thr->pool = pool; snprintf(name, sizeof(name), "iv_work pool %p thread %p", pool, thr); ret = iv_thread_create(name, iv_work_thread, thr); if (ret < 0) { free(thr); return -1; } pool->started_threads++; return 0; } static void iv_work_submit_pool(struct iv_work_pool *this, struct iv_work_item *work) { struct work_pool_priv *pool = this->priv; mutex_lock(&pool->lock); pool->seq_tail++; iv_list_add_tail(&work->list, &pool->work_items); if (!iv_list_empty(&pool->idle_threads)) { struct work_pool_thread *thr; thr = iv_container_of(pool->idle_threads.next, struct work_pool_thread, list); thr->kicked = 1; iv_event_post(&thr->kick); } else if (pool->started_threads < this->max_threads) { iv_work_start_thread(pool); } mutex_unlock(&pool->lock); } struct iv_work_thr_info { struct iv_task task; struct iv_list_head work_items; }; static void iv_work_handle_local(void *_tinfo); static void iv_work_tls_init_thread(void *_tinfo) { struct iv_work_thr_info *tinfo = _tinfo; IV_TASK_INIT(&tinfo->task); tinfo->task.cookie = tinfo; tinfo->task.handler = iv_work_handle_local; INIT_IV_LIST_HEAD(&tinfo->work_items); } static struct iv_tls_user iv_work_tls_user = { .sizeof_state = sizeof(struct iv_work_thr_info), .init_thread = iv_work_tls_init_thread, }; static void iv_work_tls_init(void) __attribute__((constructor)); static void iv_work_tls_init(void) { iv_tls_user_register(&iv_work_tls_user); } static void iv_work_handle_local(void *_tinfo) { struct iv_work_thr_info *tinfo = _tinfo; struct iv_list_head items; __iv_list_steal_elements(&tinfo->work_items, &items); while (!iv_list_empty(&items)) { struct iv_work_item *work; work = iv_container_of(items.next, struct iv_work_item, list); iv_list_del(&work->list); work->work(work->cookie); work->completion(work->cookie); } } static void iv_work_submit_local(struct iv_work_item *work) { struct iv_work_thr_info *tinfo = iv_tls_user_ptr(&iv_work_tls_user); if (iv_list_empty(&tinfo->work_items)) iv_task_register(&tinfo->task); iv_list_add_tail(&work->list, &tinfo->work_items); } void iv_work_pool_submit_work(struct iv_work_pool *this, struct iv_work_item *work) { if (this != NULL) iv_work_submit_pool(this, work); else iv_work_submit_local(work); } ivykis-0.36.2/src/mutex.h000066400000000000000000000031561210744026200152250ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _WIN32 #include typedef pthread_mutex_t __mutex_t; static inline int mutex_init(__mutex_t *mutex) { return pthread_mutex_init(mutex, NULL); } static inline void mutex_destroy(__mutex_t *mutex) { pthread_mutex_destroy(mutex); } static inline void mutex_lock(__mutex_t *mutex) { pthread_mutex_lock(mutex); } static inline void mutex_unlock(__mutex_t *mutex) { pthread_mutex_unlock(mutex); } #else typedef CRITICAL_SECTION __mutex_t; static inline int mutex_init(__mutex_t *mutex) { InitializeCriticalSection(mutex); return 0; } static inline void mutex_destroy(__mutex_t *mutex) { DeleteCriticalSection(mutex); } static inline void mutex_lock(__mutex_t *mutex) { EnterCriticalSection(mutex); } static inline void mutex_unlock(__mutex_t *mutex) { LeaveCriticalSection(mutex); } #endif ivykis-0.36.2/src/spinlock.h000066400000000000000000000040121210744026200156750ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "config.h" #if defined(HAVE_PTHREAD_SPIN_LOCK) #define spinlock_t pthread_spinlock_t static inline void spin_init(spinlock_t *lock) { pthread_spin_init(lock, PTHREAD_PROCESS_SHARED); } static inline void spin_lock(spinlock_t *lock) { pthread_spin_lock(lock); } static inline void spin_unlock(spinlock_t *lock) { pthread_spin_unlock(lock); } #elif defined(HAVE_SYNC_LOCK_TEST_AND_SET) typedef unsigned long spinlock_t; static inline void spin_init(spinlock_t *lock) { *lock = 0; } static inline void spin_lock(spinlock_t *lock) { while (__sync_lock_test_and_set(lock, 1) == 1) ; } static inline void spin_unlock(spinlock_t *lock) { __sync_lock_release(lock); } #else #warning USING DUMMY SPINLOCK IMPLEMENTATION typedef unsigned long spinlock_t; static inline void spin_init(spinlock_t *lock) { } static inline void spin_lock(spinlock_t *lock) { } static inline void spin_unlock(spinlock_t *lock) { } #endif static inline void spin_lock_sigmask(spinlock_t *lock, sigset_t *mask) { sigfillset(mask); pthread_sigmask(SIG_BLOCK, mask, mask); spin_lock(lock); } static inline void spin_unlock_sigmask(spinlock_t *lock, sigset_t *mask) { spin_unlock(lock); pthread_sigmask(SIG_SETMASK, mask, NULL); } ivykis-0.36.2/test/000077500000000000000000000000001210744026200140755ustar00rootroot00000000000000ivykis-0.36.2/test/Makefile.am000066400000000000000000000031321210744026200161300ustar00rootroot00000000000000AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/src/include \ -I$(top_builddir)/src/include LDADD = $(top_builddir)/src/libivykis.la PROGS = iv_event_test \ iv_thread_test \ iv_work_test TESTS = avl \ iv_event_raw_test \ struct_sizes \ timer \ timer_order if HAVE_POSIX PROGS += client \ connectfail \ connectreset \ iv_fd_pump_discard \ iv_fd_pump_echo \ iv_popen_test \ iv_signal_child_test \ iv_wait_test \ null \ server \ server_thread if HAVE_INOTIFY PROGS += iv_inotify_test endif TESTS += iv_signal_test endif if HAVE_WIN32 PROGS += handle endif noinst_PROGRAMS = $(PROGS) $(TESTS) avl_SOURCES = avl.c client_SOURCES = client.c connectfail_SOURCES = connectfail.c connectreset_SOURCES = connectreset.c handle_SOURCES = handle.c iv_event_raw_test_SOURCES = iv_event_raw_test.c iv_event_test_SOURCES = iv_event_test.c iv_fd_pump_discard_SOURCES = iv_fd_pump_discard.c iv_fd_pump_echo_SOURCES = iv_fd_pump_echo.c iv_popen_test_SOURCES = iv_popen_test.c iv_signal_child_test_SOURCES = iv_signal_child_test.c iv_signal_test_SOURCES = iv_signal_test.c iv_thread_test_SOURCES = iv_thread_test.c iv_wait_test_SOURCES = iv_wait_test.c iv_work_test_SOURCES = iv_work_test.c null_SOURCES = null.c server_SOURCES = server.c struct_sizes_SOURCES = struct_sizes.c timer_SOURCES = timer.c timer_order_SOURCES = timer_order.c server_thread_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/src/include -I$(top_builddir)/src/include -DTHREAD server_thread_SOURCES = server.c ivykis-0.36.2/test/avl.c000066400000000000000000000076341210744026200150350ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include struct node { struct iv_avl_node an; int num; }; static struct iv_avl_tree x; static void tree_node_print(int depth, struct iv_avl_node *an) { struct node *f = iv_container_of(an, struct node, an); int i; for (i = 0; i < depth; i++) fprintf(stderr, " "); fprintf(stderr, "%p (parent=%p): %d (height %d)\n", an, an->parent, f->num, f->an.height); if (an->left != NULL) tree_node_print(depth + 1, an->left); if (an->right != NULL) tree_node_print(depth + 1, an->right); } static void tree_print(char *msg) { fprintf(stderr, "%s:\n", msg); if (x.root != NULL) tree_node_print(0, x.root); fprintf(stderr, "\n"); } static void __attribute__((noreturn)) fatal(const char *fmt, ...) { va_list ap; char msg[1024]; va_start(ap, fmt); vsnprintf(msg, sizeof(msg), fmt, ap); va_end(ap); msg[sizeof(msg) - 1] = 0; tree_print(msg); exit(1); } static int tree_node_verify(struct iv_avl_tree *this, struct iv_avl_node *an, struct iv_avl_node *parent, struct iv_avl_node *min, struct iv_avl_node *max, int *cnt) { int hl; int hr; int my; if (an->parent != parent) { fatal("parent mismatch: %p, %p versus %p", an, an->parent, parent); } (*cnt)++; if (min != NULL || max != NULL) { int err; err = 0; if (min != NULL && this->compare(min, an) >= 0) err++; if (max != NULL && this->compare(an, max) >= 0) err++; if (err) fatal("violated %p < %p < %p", min, an, max); } hl = 0; if (an->left != NULL) hl = tree_node_verify(this, an->left, an, min, an, cnt); hr = 0; if (an->right != NULL) hr = tree_node_verify(this, an->right, an, an, max, cnt); if (abs(hl - hr) > 1) fatal("balance mismatch: %d vs %d", hl, hr); my = 1 + ((hl > hr) ? hl : hr); if (an->height != my) fatal("height mismatch: %d vs %d/%d", an->height, hl, hr); return my; } static void tree_check(struct iv_avl_tree *this, int expected_count) { int count; count = 0; if (this->root != NULL) tree_node_verify(this, this->root, NULL, NULL, NULL, &count); if (expected_count >= 0 && expected_count != count) fatal("count mismatch: %d versus %d", count, expected_count); } #define NUM 16384 static struct node *f[NUM]; static int docomp(struct iv_avl_node *_a, struct iv_avl_node *_b) { struct node *a = iv_container_of(_a, struct node, an); struct node *b = iv_container_of(_b, struct node, an); if (a->num < b->num) return -1; if (a->num > b->num) return 1; return 0; } static int mkrand(void) { int r; r = rand(); #if RAND_MAX == 0x7fff r |= rand() << 15; #endif return r; } int main() { int i; alarm(300); srand(time(NULL) ^ getpid()); INIT_IV_AVL_TREE(&x, docomp); tree_check(&x, 0); for (i = 0; i < NUM; i++) { int ret; f[i] = malloc(sizeof(struct node)); do { f[i]->num = mkrand(); ret = iv_avl_tree_insert(&x, &f[i]->an); } while (ret < 0); tree_check(&x, i + 1); } for (i = 0; i < NUM; i++) { iv_avl_tree_delete(&x, &f[i]->an); tree_check(&x, NUM - i - 1); free(f[i]); } return 0; } ivykis-0.36.2/test/client.c000066400000000000000000000050421210744026200155200ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include struct connector { struct sockaddr_in addr; struct iv_fd fd; }; static void create_connector(struct connector *conn); static int __connect_done(struct connector *conn) { socklen_t len; int ret; len = sizeof(ret); if (getsockopt(conn->fd.fd, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { fprintf(stderr, "connect_done: error %d while " "getsockopt(SO_ERROR)\n", errno); abort(); } if (ret == EINPROGRESS) return 0; if (ret) fprintf(stderr, "blah: %s\n", strerror(ret)); #if 0 fprintf(stderr, "."); #endif iv_fd_unregister(&conn->fd); close(conn->fd.fd); return 1; } static void connect_done(void *c) { struct connector *conn = (struct connector *)c; if (__connect_done(conn)) create_connector(conn); } static void create_connector(struct connector *conn) { int fd; int ret; again: fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); exit(1); } IV_FD_INIT(&conn->fd); conn->fd.fd = fd; conn->fd.cookie = (void *)conn; conn->fd.handler_out = connect_done; iv_fd_register(&conn->fd); ret = connect(fd, (struct sockaddr *)&conn->addr, sizeof(conn->addr)); if ((ret == 0 || errno != EINPROGRESS) && __connect_done(conn)) goto again; } int main() { struct sockaddr_in addr; struct connector c[1000]; int i; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(0x7f000001); iv_init(); for (i = 0; i < sizeof(c) / sizeof(c[0]); i++) { struct connector *conn = c + i; conn->addr = addr; conn->addr.sin_port = htons(20000 + i); create_connector(conn); } iv_main(); iv_deinit(); return 0; } ivykis-0.36.2/test/connectfail.c000066400000000000000000000035661210744026200165400ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include static struct iv_fd ifd; static void connect_done(void *_dummy) { socklen_t len; int ret; len = sizeof(ret); if (getsockopt(ifd.fd, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { fprintf(stderr, "connect_done: error %d while " "getsockopt(SO_ERROR)\n", errno); abort(); } if (ret == EINPROGRESS) return; if (ret) fprintf(stderr, "blah: %s\n", strerror(ret)); iv_fd_set_handler_out(&ifd, NULL); } int main() { int fd; struct sockaddr_in addr; int ret; iv_init(); fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); exit(1); } IV_FD_INIT(&ifd); ifd.fd = fd; ifd.handler_out = connect_done; iv_fd_register(&ifd); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(0x7f000001); addr.sin_port = htons(6667); ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); if (ret == 0 || errno != EINPROGRESS) connect_done(NULL); iv_main(); iv_deinit(); return 0; } ivykis-0.36.2/test/connectreset.c000066400000000000000000000074411210744026200167430ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include /* SERVER ********************************************************************/ struct client_connection { struct iv_fd fd; struct iv_timer tim; }; static struct iv_fd server_socket; static void timeout(void *_c) { struct client_connection *c = (struct client_connection *)_c; struct linger l; iv_fd_unregister(&c->fd); /* Force a TCP RST on close. */ l.l_onoff = 1; l.l_linger = 0; setsockopt(c->fd.fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)); close(c->fd.fd); free(c); } static void got_connection(void *_dummy) { struct client_connection *c; struct sockaddr_in addr; socklen_t addrlen; int ret; addrlen = sizeof(addr); ret = accept(server_socket.fd, (struct sockaddr *)&addr, &addrlen); if (ret < 0) { if (errno != EAGAIN) { perror("accept"); abort(); } return; } c = malloc(sizeof(*c)); if (c == NULL) { close(ret); return; } IV_FD_INIT(&c->fd); c->fd.fd = ret; c->fd.cookie = (void *)c; iv_fd_register(&c->fd); IV_TIMER_INIT(&c->tim); c->tim.cookie = (void *)c; c->tim.handler = timeout; iv_validate_now(); c->tim.expires = iv_now; c->tim.expires.tv_sec += 1; iv_timer_register(&c->tim); } static void server_init(void) { struct sockaddr_in addr; int sock; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); abort(); } addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(6667); if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); abort(); } listen(sock, 5); IV_FD_INIT(&server_socket); server_socket.fd = sock; server_socket.handler_in = got_connection; iv_fd_register(&server_socket); } /* CLIENT ********************************************************************/ static struct iv_fd ifd; static void got_reset(void *_dummy) { printf("reset caught\n"); iv_fd_set_handler_err(&ifd, NULL); } static void connect_done(void *_dummy) { socklen_t len; int ret; len = sizeof(ret); if (getsockopt(ifd.fd, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { fprintf(stderr, "connect_done: error %d while " "getsockopt(SO_ERROR)\n", errno); abort(); } if (ret == EINPROGRESS) return; iv_fd_set_handler_out(&ifd, NULL); if (ret) { fprintf(stderr, "connect: %s\n", strerror(ret)); iv_quit(); } else { iv_fd_set_handler_err(&ifd, got_reset); } } int main() { int fd; struct sockaddr_in addr; int ret; iv_init(); server_init(); fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); exit(1); } IV_FD_INIT(&ifd); ifd.fd = fd; ifd.cookie = NULL; ifd.handler_out = connect_done; iv_fd_register(&ifd); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(0x7f000001); addr.sin_port = htons(6667); ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); if (ret == 0 || errno != EINPROGRESS) connect_done(NULL); iv_main(); iv_deinit(); return 0; } ivykis-0.36.2/test/handle.c000066400000000000000000000030221210744026200154710ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2012 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include static int foo; static void handle_active(void *_h) { struct iv_handle *h = _h; printf("got handle event\n"); Sleep(100); printf("returning\n"); if (++foo > 10) iv_handle_unregister(h); } static DWORD CALLBACK thread(void *_h) { struct iv_handle *h = _h; while (1) { SetEvent(h->handle); Sleep(1000); } return 0; } int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { struct iv_handle h; iv_init(); IV_HANDLE_INIT(&h); h.handle = CreateEvent(NULL, FALSE, FALSE, NULL); h.cookie = &h; h.handler = handle_active; iv_handle_register(&h); CreateThread(NULL, 0, thread, &h, 0, NULL); iv_main(); return 0; } ivykis-0.36.2/test/iv_event_raw_test.c000066400000000000000000000031621210744026200177720ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include static struct iv_event_raw ev0; static struct iv_timer ev1; static struct iv_event_raw ev2; static int success; static void gotev2(void *_x) { iv_event_raw_unregister(&ev2); success = 1; } static void gotev1(void *_x) { IV_EVENT_RAW_INIT(&ev2); ev2.handler = gotev2; iv_event_raw_register(&ev2); iv_event_raw_post(&ev2); } static void gotev0(void *_x) { iv_event_raw_unregister(&ev0); IV_TIMER_INIT(&ev1); iv_validate_now(); ev1.expires = iv_now; ev1.expires.tv_nsec += 100000000; ev1.handler = gotev1; iv_timer_register(&ev1); } int main() { alarm(5); iv_init(); IV_EVENT_RAW_INIT(&ev0); ev0.handler = gotev0; iv_event_raw_register(&ev0); iv_event_raw_post(&ev0); iv_main(); iv_deinit(); return !success; } ivykis-0.36.2/test/iv_event_test.c000066400000000000000000000042721210744026200171240ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include static struct iv_event ev0; static struct iv_timer tim0; static struct iv_event ev1; static struct iv_timer tim1; static void got_ev0(void *_dummy) { printf("%lu: got ev0, starting tim0\n", iv_thread_get_id()); iv_validate_now(); tim0.expires = iv_now; tim0.expires.tv_sec++; iv_timer_register(&tim0); } static void got_tim0(void *_dummy) { printf("%lu: tim0 expired, signaling ev1\n", iv_thread_get_id()); iv_event_post(&ev1); } static void got_ev1(void *_dummy) { printf("%lu: got ev1, starting tim1\n", iv_thread_get_id()); iv_validate_now(); tim1.expires = iv_now; tim1.expires.tv_sec++; iv_timer_register(&tim1); } static void got_tim1(void *_dummy) { printf("%lu: tim1 expired, signaling ev0\n", iv_thread_get_id()); iv_event_post(&ev0); } static void thread1(void *_dummy) { iv_init(); IV_EVENT_INIT(&ev1); ev1.handler = got_ev1; iv_event_register(&ev1); IV_TIMER_INIT(&tim1); tim1.handler = got_tim1; iv_main(); } int main() { iv_init(); IV_EVENT_INIT(&ev0); ev0.handler = got_ev0; iv_event_register(&ev0); IV_TIMER_INIT(&tim0); tim0.handler = got_tim0; iv_thread_create("thread1", thread1, NULL); iv_validate_now(); tim0.expires = iv_now; tim0.expires.tv_sec++; iv_timer_register(&tim0); iv_main(); iv_deinit(); return 0; } ivykis-0.36.2/test/iv_fd_pump_discard.c000066400000000000000000000060171210744026200200660ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2009, 2011 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include struct connection { struct iv_fd sock; struct iv_fd_pump pump; }; static int devnull; static void conn_pump(void *_conn) { struct connection *conn = (struct connection *)_conn; if (iv_fd_pump_pump(&conn->pump) <= 0) { iv_fd_pump_destroy(&conn->pump); iv_fd_unregister(&conn->sock); close(conn->sock.fd); free(conn); } } static void conn_set_bands(void *_conn, int pollin, int pollout) { struct connection *conn = (struct connection *)_conn; iv_fd_set_handler_in(&conn->sock, pollin ? conn_pump : NULL); if (pollout) printf("conn_set_bands: pollout is set?!\n"); } static struct iv_fd listening_socket; static void got_connection(void *_dummy) { struct sockaddr_in addr; struct connection *conn; socklen_t addrlen; int ret; addrlen = sizeof(addr); ret = accept(listening_socket.fd, (struct sockaddr *)&addr, &addrlen); if (ret < 0) return; conn = malloc(sizeof(*conn)); if (conn == NULL) { fprintf(stderr, "memory squeeze\n"); abort(); } IV_FD_INIT(&conn->sock); conn->sock.fd = ret; conn->sock.cookie = (void *)conn; iv_fd_register(&conn->sock); IV_FD_PUMP_INIT(&conn->pump); conn->pump.from_fd = ret; conn->pump.to_fd = devnull; conn->pump.cookie = conn; conn->pump.set_bands = conn_set_bands; conn->pump.flags = 0; iv_fd_pump_init(&conn->pump); } static int open_listening_socket(void) { struct sockaddr_in addr; int sock; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); return 1; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(10009); if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); return 1; } listen(sock, 5); IV_FD_INIT(&listening_socket); listening_socket.fd = sock; listening_socket.cookie = NULL; listening_socket.handler_in = got_connection; iv_fd_register(&listening_socket); return 0; } int main() { devnull = open("/dev/null", O_WRONLY); if (devnull < 0) { perror("open /dev/null"); return 1; } iv_init(); open_listening_socket(); iv_main(); return 0; } ivykis-0.36.2/test/iv_fd_pump_echo.c000066400000000000000000000055751210744026200174030ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003, 2009, 2011 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include struct connection { struct iv_fd sock; struct iv_fd_pump pump; }; static void conn_pump(void *_conn) { struct connection *conn = (struct connection *)_conn; if (iv_fd_pump_pump(&conn->pump) <= 0) { iv_fd_pump_destroy(&conn->pump); iv_fd_unregister(&conn->sock); close(conn->sock.fd); free(conn); } } static void conn_set_bands(void *_conn, int pollin, int pollout) { struct connection *conn = (struct connection *)_conn; iv_fd_set_handler_in(&conn->sock, pollin ? conn_pump : NULL); iv_fd_set_handler_out(&conn->sock, pollout ? conn_pump : NULL); } static struct iv_fd listening_socket; static void got_connection(void *_dummy) { struct sockaddr_in addr; struct connection *conn; socklen_t addrlen; int ret; addrlen = sizeof(addr); ret = accept(listening_socket.fd, (struct sockaddr *)&addr, &addrlen); if (ret < 0) return; conn = malloc(sizeof(*conn)); if (conn == NULL) { fprintf(stderr, "memory squeeze\n"); abort(); } IV_FD_INIT(&conn->sock); conn->sock.fd = ret; conn->sock.cookie = (void *)conn; iv_fd_register(&conn->sock); IV_FD_PUMP_INIT(&conn->pump); conn->pump.from_fd = ret; conn->pump.to_fd = ret; conn->pump.cookie = conn; conn->pump.set_bands = conn_set_bands; conn->pump.flags = 0; iv_fd_pump_init(&conn->pump); } static int open_listening_socket(void) { struct sockaddr_in addr; int sock; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); return 1; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(6969); if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); return 1; } listen(sock, 5); IV_FD_INIT(&listening_socket); listening_socket.fd = sock; listening_socket.cookie = NULL; listening_socket.handler_in = got_connection; iv_fd_register(&listening_socket); return 0; } int main() { iv_init(); open_listening_socket(); iv_main(); return 0; } ivykis-0.36.2/test/iv_inotify_test.c000066400000000000000000000060351210744026200174630ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2008, 2009 Ronald Huizer * Dedicated to Kanna Ishihara. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include static void print_event(int mask) { if (mask & IN_ACCESS) { mask &= ~IN_ACCESS; printf(" IN_ACCESS"); } if (mask & IN_ATTRIB) { mask &= ~IN_ATTRIB; printf(" IN_ATTRIB"); } if (mask & IN_CLOSE_WRITE) { mask &= ~IN_CLOSE_WRITE; printf(" IN_CLOSE_WRITE"); } if (mask & IN_CLOSE_NOWRITE) { mask &= ~IN_CLOSE_NOWRITE; printf(" IN_CLOSE_NOWRITE"); } if (mask & IN_CREATE) { mask &= ~IN_CREATE; printf(" IN_CREATE"); } if (mask & IN_DELETE) { mask &= ~IN_DELETE; printf(" IN_DELETE"); } if (mask & IN_DELETE_SELF) { mask &= ~IN_DELETE_SELF; printf(" IN_DELETE_SELF"); } if (mask & IN_MODIFY) { mask &= ~IN_MODIFY; printf(" IN_MODIFY"); } if (mask & IN_MOVE_SELF) { mask &= ~IN_MOVE_SELF; printf(" IN_MOVE_SELF"); } if (mask & IN_MOVED_FROM) { mask &= ~IN_MOVED_FROM; printf(" IN_MOVED_FROM"); } if (mask & IN_MOVED_TO) { mask &= ~IN_MOVED_TO; printf(" IN_MOVED_TO"); } if (mask & IN_OPEN) { mask &= ~IN_OPEN; printf(" IN_OPEN"); } if (mask & IN_IGNORED) { mask &= ~IN_IGNORED; printf(" IN_IGNORED"); } if (mask & IN_ISDIR) { mask &= ~IN_ISDIR; printf(" IN_ISDIR"); } if (mask & IN_Q_OVERFLOW) { mask &= ~IN_Q_OVERFLOW; printf(" IN_Q_OVERFLOW"); } if (mask & IN_UNMOUNT) { mask &= ~IN_UNMOUNT; printf(" IN_UNMOUNT"); } if (mask != 0) printf(" 0x%.8x", mask); } static void test_handler(void *_w, struct inotify_event *event) { struct iv_inotify_watch *w = _w; printf("%s", w->pathname); if (event->len != 0) printf("/%s", event->name); printf(":"); print_event(event->mask); printf("\n"); } int main(int argc, char **argv) { struct iv_inotify inotify; int i; if (argc < 2) { fprintf(stderr, "Usage: %s FILE...\n", argv[0]); return 1; } iv_init(); IV_INOTIFY_INIT(&inotify); iv_inotify_register(&inotify); for (i = 1; i < argc; i++) { struct iv_inotify_watch *w; w = malloc(sizeof(*w)); if (w == NULL) { perror("malloc"); return 1; } IV_INOTIFY_WATCH_INIT(w); w->inotify = &inotify; w->pathname = argv[i]; w->mask = IN_ALL_EVENTS; w->cookie = w; w->handler = test_handler; iv_inotify_watch_register(w); } iv_main(); iv_deinit(); return 0; } ivykis-0.36.2/test/iv_popen_test.c000066400000000000000000000052011210744026200171150ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #define NUM 4 struct req { struct iv_popen_request popen_req; char *argv[3]; struct iv_fd popen_fd; struct iv_timer closeit; }; static void done(struct req *req, int timeout) { iv_popen_request_close(&req->popen_req); iv_fd_unregister(&req->popen_fd); close(req->popen_fd.fd); if (!timeout) iv_timer_unregister(&req->closeit); } static void got_data(void *_req) { struct req *req = _req; char buf[1024]; int ret; ret = read(req->popen_fd.fd, buf, sizeof(buf)); if (ret <= 0) { if (ret == 0) { fprintf(stderr, "got EOF\n"); done(req, 0); } else if (errno != EAGAIN && errno != EINTR) { perror("read"); done(req, 0); } return; } printf("%p: ", req); fwrite(buf, 1, ret, stdout); } static void do_close(void *_req) { struct req *req = _req; printf("%p: timeout expired, closing the popen request\n", req); done(req, 1); } static void open_child_request(struct req *req) { int f; IV_POPEN_REQUEST_INIT(&req->popen_req); req->popen_req.file = "/usr/bin/vmstat"; req->argv[0] = "/usr/bin/vmstat"; req->argv[1] = "1"; req->argv[2] = NULL; req->popen_req.argv = req->argv; req->popen_req.type = "r"; f = iv_popen_request_submit(&req->popen_req); printf("submitted the popen request, fd is %d\n", f); IV_FD_INIT(&req->popen_fd); req->popen_fd.fd = f; req->popen_fd.cookie = req; req->popen_fd.handler_in = got_data; iv_fd_register(&req->popen_fd); IV_TIMER_INIT(&req->closeit); iv_validate_now(); req->closeit.expires = iv_now; req->closeit.expires.tv_sec += 5; req->closeit.cookie = req; req->closeit.handler = do_close; iv_timer_register(&req->closeit); } int main() { struct req req[NUM]; int i; iv_init(); for (i = 0; i < NUM; i++) open_child_request(&req[i]); iv_main(); iv_deinit(); return 0; } ivykis-0.36.2/test/iv_signal_child_test.c000066400000000000000000000030501210744026200204140ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include static struct iv_signal is_sigterm; static void got_sigterm(void *_x) { printf("got SIGTERM in parent process, race?\n"); } int main() { char *argv[3]; struct iv_popen_request popen_req; iv_init(); IV_SIGNAL_INIT(&is_sigterm); is_sigterm.signum = SIGTERM; is_sigterm.handler = got_sigterm; iv_signal_register(&is_sigterm); IV_POPEN_REQUEST_INIT(&popen_req); popen_req.file = "/bin/sleep"; argv[0] = "/bin/sleep"; argv[1] = "3600"; argv[2] = NULL; popen_req.argv = argv; popen_req.type = "r"; iv_popen_request_submit(&popen_req); iv_popen_request_close(&popen_req); iv_main(); iv_deinit(); return 0; } ivykis-0.36.2/test/iv_signal_test.c000066400000000000000000000024311210744026200172530ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include static struct iv_signal is_sigusr1; static int success; static void got_sigusr1(void *_x) { iv_signal_unregister(&is_sigusr1); success = 1; } int main() { alarm(5); iv_init(); IV_SIGNAL_INIT(&is_sigusr1); is_sigusr1.signum = SIGUSR1; is_sigusr1.handler = got_sigusr1; iv_signal_register(&is_sigusr1); raise(SIGUSR1); iv_main(); iv_deinit(); return !success; } ivykis-0.36.2/test/iv_thread_test.c000066400000000000000000000026761210744026200172600ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #ifndef _WIN32 #include #endif static void thr_return(void *cookie) { } #ifndef _WIN32 static void thr_selfcancel(void *cookie) { pthread_cancel(pthread_self()); pthread_testcancel(); } static void thr_exit(void *cookie) { pthread_exit(NULL); } #endif int main() { iv_init(); iv_thread_set_debug_state(1); iv_thread_create("return", thr_return, NULL); #ifndef _WIN32 iv_thread_create("selfcancel", thr_selfcancel, NULL); iv_thread_create("exit", thr_exit, NULL); #endif iv_thread_list_children(); iv_main(); iv_deinit(); return 0; } ivykis-0.36.2/test/iv_wait_test.c000066400000000000000000000062051210744026200167450ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include static void handler(void *cookie, int status, struct rusage *rusage) { struct iv_wait_interest *this = cookie; printf("wait4: status of pid %d is %.4x: ", (int)this->pid, status); if (WIFSTOPPED(status)) printf("stopped by signal %d\n", WSTOPSIG(status)); /* * On FreeBSD, WIFCONTINUED(status) => WIFSIGNALED(status). */ #ifdef WIFCONTINUED if (WIFCONTINUED(status)) { printf("resumed by delivery of SIGCONT\n"); } else #endif if (WIFSIGNALED(status)) { printf("terminated by signal %d, core %s\n", WTERMSIG(status), #ifdef WCOREDUMP WCOREDUMP(status) ? "dumped" : "not dumped"); #else "dump status unknown"); #endif iv_wait_interest_unregister(this); } if (WIFEXITED(status)) { printf("exited with status %d\n", WEXITSTATUS(status)); iv_wait_interest_unregister(this); } } static void dosleep(int msec) { struct timeval curtime; struct timeval until; gettimeofday(&curtime, NULL); until = curtime; until.tv_sec += msec / 1000; until.tv_usec += (msec % 1000) * 1000; if (until.tv_usec >= 1000000) { until.tv_sec++; until.tv_usec -= 1000000; } while (1) { struct timeval tv; tv.tv_sec = until.tv_sec - curtime.tv_sec; tv.tv_usec = until.tv_usec - curtime.tv_usec; if (tv.tv_usec < 0) { tv.tv_sec--; tv.tv_usec += 1000000; } if (tv.tv_sec < 0 || select(0, NULL, NULL, NULL, &tv) == 0) break; gettimeofday(&curtime, NULL); } } static void thr(void *cookie) { int pid = (int)(unsigned long)cookie; dosleep(2500); printf("sending child SIGSTOP\n"); kill(pid, SIGSTOP); dosleep(2500); printf("sending child SIGCONT\n"); kill(pid, SIGCONT); dosleep(2500); printf("sending child SIGTERM\n"); kill(pid, SIGTERM); } static void child(void *cookie) { int i; for (i = 0; i < 10; i++) { printf("child sleeping %d\n", i); dosleep(1000); } printf("dying\n"); exit(0); } int main() { struct iv_wait_interest this; int ret; iv_init(); IV_WAIT_INTEREST_INIT(&this); this.cookie = &this; this.handler = handler; ret = iv_wait_interest_register_spawn(&this, child, NULL); if (ret < 0) { perror("fork"); return -1; } iv_thread_create("thr", thr, (void *)(unsigned long)this.pid); iv_main(); iv_deinit(); return 0; } ivykis-0.36.2/test/iv_work_test.c000066400000000000000000000044631210744026200167670ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2010 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * This library 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include static struct iv_work_pool pool; static struct iv_work_item item_a; static struct iv_work_item item_b; static struct iv_work_item item_c; static struct iv_work_item item_d; static int item_count; static void work(void *cookie) { char *task = cookie; printf("performing work item %s in thread %lu\n", task, iv_thread_get_id()); #ifndef _WIN32 sleep(1); #else Sleep(1000); #endif } static void work_complete(void *cookie) { char *task = cookie; printf("notification that work item %s is complete\n", task); item_count--; if (item_count == 3) { printf("putting pool\n"); iv_work_pool_put(&pool); } } int main() { iv_init(); iv_thread_set_debug_state(1); IV_WORK_POOL_INIT(&pool); pool.max_threads = 8; iv_work_pool_create(&pool); IV_WORK_ITEM_INIT(&item_a); item_a.cookie = "a"; item_a.work = work; item_a.completion = work_complete; iv_work_pool_submit_work(&pool, &item_a); IV_WORK_ITEM_INIT(&item_b); item_b.cookie = "b"; item_b.work = work; item_b.completion = work_complete; iv_work_pool_submit_work(&pool, &item_b); IV_WORK_ITEM_INIT(&item_c); item_c.cookie = "c"; item_c.work = work; item_c.completion = work_complete; iv_work_pool_submit_work(&pool, &item_c); IV_WORK_ITEM_INIT(&item_d); item_d.cookie = "d"; item_d.work = work; item_d.completion = work_complete; iv_work_pool_submit_work(&pool, &item_d); item_count = 4; iv_main(); iv_deinit(); return 0; } ivykis-0.36.2/test/null.c000066400000000000000000000021041210744026200152100ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include int main() { struct iv_fd fd; iv_init(); IV_FD_INIT(&fd); fd.fd = 0; fd.cookie = NULL; fd.handler_in = NULL; fd.handler_out = NULL; iv_fd_register(&fd); iv_main(); iv_deinit(); return 0; } ivykis-0.36.2/test/server.c000066400000000000000000000060421210744026200155510ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include struct handle { struct iv_fd fd; int port; }; static int conns; static void handler(void *_h) { struct handle *h = (struct handle *)_h; struct sockaddr_in addr; socklen_t addrlen; int ret; addrlen = sizeof(addr); ret = accept(h->fd.fd, (struct sockaddr *)&addr, &addrlen); if (ret > 0) { char buf[128]; int len; len = snprintf(buf, 128, "this is port %d\n", h->port); write(ret, buf, len); close(ret); if (!(++conns % 10000)) printf("%i\n", conns); } } static void create_handle(struct handle *h, int port) { struct sockaddr_in addr; int sock; int yes; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); exit(1); } yes = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { perror("setsockopt"); exit(1); } addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(port); if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); exit(1); } listen(sock, 5); IV_FD_INIT(&h->fd); h->fd.fd = sock; h->fd.handler_in = handler; h->fd.handler_out = NULL; h->fd.cookie = h; h->port = port; iv_fd_register(&h->fd); } static void create_run_handles(int fp, int numhandles) { struct handle hh[numhandles]; int i; printf("entering main loop for ports %d..%d\n", fp, fp + numhandles - 1); for (i = 0; i < numhandles; i++) create_handle(hh + i, fp + i); iv_main(); iv_deinit(); } #ifndef __hpux__ #define NUMPORTS 100 #else #define NUMPORTS 4 #endif #ifdef THREAD #include static void *thr(void *_fp) { int fp = (int)(unsigned long)_fp; iv_init(); create_run_handles(fp, NUMPORTS); return NULL; } int main() { int i; iv_init(); for (i = 1; i < 10; i++) { unsigned long fp = 20000 + i * NUMPORTS; pthread_t id; pthread_create(&id, NULL, thr, (void *)fp); } create_run_handles(20000, NUMPORTS); return 0; } #else int main() { iv_init(); create_run_handles(20000, 10 * NUMPORTS); return 0; } #endif ivykis-0.36.2/test/struct_sizes.c000066400000000000000000000043101210744026200170000ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include "../iv_private.h" #ifndef _WIN32 #include "../iv_fd_private.h" #else #include "../iv_handle_private.h" #endif int main() { int fail; fail = 0; #ifndef _WIN32 if (sizeof(struct iv_fd) < sizeof(struct iv_fd_)) { fprintf(stderr, "struct iv_fd: %d\n", (int)sizeof(struct iv_fd)); fprintf(stderr, "struct iv_fd_: %d\n", (int)sizeof(struct iv_fd_)); fprintf(stderr, "\t=> TOO SMALL\n"); fprintf(stderr, "\n"); fail = 1; } #else if (sizeof(struct iv_handle) < sizeof(struct iv_handle_)) { fprintf(stderr, "struct iv_handle: %d\n", (int)sizeof(struct iv_handle)); fprintf(stderr, "struct iv_handle_: %d\n", (int)sizeof(struct iv_handle_)); fprintf(stderr, "\t=> TOO SMALL\n"); fprintf(stderr, "\n"); fail = 1; } #endif if (sizeof(struct iv_task) < sizeof(struct iv_task_)) { fprintf(stderr, "struct iv_task: %d\n", (int)sizeof(struct iv_task)); fprintf(stderr, "struct iv_task_: %d\n", (int)sizeof(struct iv_task_)); fprintf(stderr, "\t=> TOO SMALL\n"); fprintf(stderr, "\n"); fail = 1; } if (sizeof(struct iv_timer) < sizeof(struct iv_timer_)) { fprintf(stderr, "struct iv_timer: %d\n", (int)sizeof(struct iv_timer)); fprintf(stderr, "struct iv_timer_: %d\n", (int)sizeof(struct iv_timer_)); fprintf(stderr, "\t=> TOO SMALL\n"); fprintf(stderr, "\n"); fail = 1; } return fail; } ivykis-0.36.2/test/timer.c000066400000000000000000000024751210744026200153710ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include static int success; static void handler(void *_t) { success = 1; } int main() { struct iv_timer timer; alarm(5); iv_init(); IV_TIMER_INIT(&timer); iv_validate_now(); timer.expires = iv_now; timer.expires.tv_nsec += 100000000; if (timer.expires.tv_nsec >= 1000000000) { timer.expires.tv_sec++; timer.expires.tv_nsec -= 1000000000; } timer.handler = handler; iv_timer_register(&timer); iv_main(); iv_deinit(); return !success; } ivykis-0.36.2/test/timer_order.c000066400000000000000000000034131210744026200165550ustar00rootroot00000000000000/* * ivykis, an event handling library * Copyright (C) 2002, 2003 Lennert Buytenhek * Dedicated to Marija Kulikova. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1 as published by the Free Software Foundation. * * 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 Lesser General Public License version 2.1 for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #ifndef __hppa__ #define NUM 1048570 #else #define NUM 32768 #endif static struct iv_timer tim[NUM]; static int expect; static void handler(void *_t) { struct iv_timer *t = (struct iv_timer *)_t; int index; index = (int)(t - tim); if (expect != index) { fprintf(stderr, "expecting %d, got %d\n", expect, index); exit(1); } expect++; } int main() { int i; alarm(30); iv_init(); iv_validate_now(); for (i = 0; i < NUM; i++) { IV_TIMER_INIT(tim + i); tim[i].expires = iv_now; tim[i].expires.tv_nsec += i + 100000000; if (tim[i].expires.tv_nsec >= 1000000000) { tim[i].expires.tv_sec++; tim[i].expires.tv_nsec -= 1000000000; } tim[i].cookie = (void *)&tim[i]; tim[i].handler = handler; iv_timer_register(&tim[i]); } iv_main(); iv_deinit(); if (expect != NUM) { fprintf(stderr, "only ran %d timer handlers (vs %d)\n", expect, NUM); return 1; } return 0; }