├── .github └── stale.yml ├── AUTHORS ├── COPYING ├── ChangeLog ├── LICENSE ├── Makefile.am ├── NOTICE ├── README.md ├── bootstrap ├── configure.in ├── jubatus └── mp │ ├── Makefile.am │ ├── endian.h │ ├── exception.h │ ├── functional.h │ ├── iocntl.h │ ├── memory.h │ ├── object_callback.hmpl │ ├── object_delete.h │ ├── pthread.h │ ├── shared_buffer.h │ ├── signal.h │ ├── sparse_array.hmpl │ ├── stream_buffer.h │ ├── sync.hmpl │ ├── tls_set.h │ ├── unordered.h │ ├── unordered_map.h │ ├── unordered_set.h │ ├── utilize.h │ └── wavy.hmpl ├── mpl.rb ├── mplex ├── mpsrc ├── Makefile.am ├── pp.h ├── wavy_connect.cc ├── wavy_kernel.h ├── wavy_kernel_epoll.h ├── wavy_kernel_kqueue.h ├── wavy_listen.cc ├── wavy_loop.cc ├── wavy_loop.h ├── wavy_out.cc ├── wavy_out.h ├── wavy_signal.cc ├── wavy_signal.h ├── wavy_timer.cc └── wavy_timer.h ├── preprocess └── test ├── Makefile.am ├── handler.cc ├── huge_message.cc ├── listen_connect.cc ├── many_timer.cc ├── signal.cc ├── sync.cc └── timer.cc /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | # Number of days of inactivity before an issue becomes stale 4 | daysUntilStale: 360 5 | # Number of days of inactivity before a stale issue is closed 6 | daysUntilClose: 90 7 | # Issues with these labels will never be considered stale 8 | exemptLabels: 9 | - bug 10 | # Label to use when marking an issue as stale 11 | staleLabel: stale 12 | # Comment to post when marking an issue as stale. Set to `false` to disable 13 | markComment: > 14 | This issue has been automatically marked as stale because it has not had 15 | recent activity. It will be closed if no further activity occurs. Thank you 16 | for your contributions. 17 | # Comment to post when removing the stale label. Set to `false` to disable 18 | unmarkComment: false 19 | # Comment to post when closing a stale issue or Pull Request. Set to `false` to disable 20 | closeComment: > 21 | Closing this issue after a prolonged period of inactivity. 22 | Please feel free to create a new issue or re-open it if you need. 23 | # Limit to only `issues` or `pulls` 24 | only: issues 25 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | FURUHASHI Sadayuki 2 | Jubatus 3 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2008-2010 FURUHASHI Sadayuki 2 | Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2014-10-20 version 0.4.5: 2 | 3 | * Fix memory leak when client is disconnected before sending back results 4 | 5 | 2014-09-29 version 0.4.4: 6 | 7 | * Fix behavior when ::accept is failed 8 | 9 | 2014-07-22 version 0.4.3: 10 | 11 | * Add -pthread option 12 | * Stop using -O4 option 13 | * Support for OS X Mavericks 14 | * Port to libc++ 15 | 16 | 2014-04-19 version 0.4.2: 17 | 18 | * Fix fd leak when timerfd is disabled on Linux 19 | * Fix event-loop dead-lock on single-large-async write 20 | 21 | 2013-02-15 version 0.4.1: 22 | 23 | * Fix header macro for clang 24 | * Fix configure.in for clang with -O4 option 25 | * Update autoconf script for distribution, exclude mplex sources 26 | 27 | 2013-01-11 version 0.4.0: 28 | 29 | * Forked from mpio. 30 | * Renamed directory mp -> jubatus/mp 31 | * Renamed libmpio -> libjubatus_mpio. 32 | * Added ruby "-I." option to preprocess 33 | * Added pthread_recursive_mutex 34 | 35 | 2011-04-22 version 0.3.7: 36 | 37 | * Added POSXI timer implementation that works on linux < 2.6.25 (Kohei++) 38 | 39 | 2011-02-20 version 0.3.6: 40 | 41 | * Fixes a potential dead-lock problem on wavy::loop::join 42 | 43 | 2010-08-16 version 0.3.5: 44 | 45 | * Adds wavy::loop::remove_handler 46 | * Fixes SEGV on kqueue-based system 47 | 48 | 2010-08-10 version 0.3.4: 49 | 50 | * Fixes stream_buffer and shared_buffer 51 | 52 | 2010-04-27 version 0.3.3: 53 | 54 | * Add wavy::loop::flush() 55 | * Add pthread_scoped_{,rd,wr}lock::owns() 56 | 57 | 2010-04-15 version 0.3.2: 58 | 59 | * Add ./configure --disable-timerfd and --disable-signalfd option 60 | * Linux < 2.6.25 (mp::wavy::add_timer is not available) and 61 | Linux < 2.6.22 (mp::wavy::add_signal is not available) are 62 | limitedly supported. 63 | 64 | 2010-04-15 version 0.3.1: 65 | 66 | * Fixes build chain; Ruby is not required to build. 67 | * add sync::get_mutex 68 | 69 | 2010-04-12 version 0.3.0: 70 | 71 | * First public release. 72 | 73 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 2 | 3 | SUBDIRS = jubatus/mp mpsrc test 4 | 5 | EXTRA_DIST = \ 6 | README.md \ 7 | LICENSE \ 8 | NOTICE 9 | 10 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | mpio is developed by FURUHASHI Sadayuki, licensed under Apache License, 2 | Version 2.0. The original software and related information is available at 3 | http://github.com/frsyuki/mpio 4 | 5 | jubatus-mpio is modified mpio for Jubatus, licenced under Apache License 6 | Version 2.0. 7 | Jubatus: Online machine learning framework for distributed environment and 8 | related informatoin is avaliable at http://jubat.us 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | jubatus-mpio 2 | ============ 3 | Multipurpose concurrent I/O framework for C++ 4 | 5 | 6 | ## Overview 7 | 8 | 9 | ## Installation 10 | 11 | Following libraries are required to build mpio: 12 | 13 | - OS 14 | - Linux >= 2.6.25 + glibc >= 2.8 15 | - Mac OS X >= 10.5 Leopard 16 | - FreeBSD >= ? 17 | - NetBSD >= ? 18 | - g++ >= 4.1 19 | 20 | Configure and install in the usual way: 21 | 22 | $ ./bootstrap # if needed 23 | $ ./configure 24 | $ make 25 | $ sudo make install 26 | 27 | 28 | ## Libraries 29 | 30 | [Test cases](http://github.com/frsyuki/mpio/tree/master/test/) will give you a sample usage. 31 | 32 | - [event handler](http://github.com/frsyuki/mpio/blob/master/test/handler.cc) 33 | - [listen and connect](http://github.com/frsyuki/mpio/blob/master/test/listen_connect.cc) 34 | - [timer](http://github.com/frsyuki/mpio/blob/master/test/timer.cc) 35 | - [signal handling](http://github.com/frsyuki/mpio/blob/master/test/signal.cc) 36 | - [mp::sync](http://github.com/frsyuki/mpio/blob/master/test/sync.cc) 37 | 38 | 39 | ### Wavy 40 | Wavy is a multithreaded event-driven I/O library. 41 | 42 | ### sync 43 | 44 | ### utilize 45 | 46 | ### shared_buffer 47 | 48 | ### stream_buffer 49 | 50 | ### sparse_array 51 | 52 | ### pthread 53 | 54 | ### signal 55 | 56 | ### functional 57 | 58 | ### memory 59 | 60 | 61 | ## License 62 | 63 | Copyright (C) 2008-2010 FURUHASHI Sadayuki 64 | Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 65 | 66 | Licensed under the Apache License, Version 2.0 (the "License"); 67 | you may not use this file except in compliance with the License. 68 | You may obtain a copy of the License at 69 | 70 | http://www.apache.org/licenses/LICENSE-2.0 71 | 72 | Unless required by applicable law or agreed to in writing, software 73 | distributed under the License is distributed on an "AS IS" BASIS, 74 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 75 | See the License for the specific language governing permissions and 76 | limitations under the License. 77 | 78 | See also NOTICE file. 79 | 80 | -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # vim:ts=4:sw=4 3 | # Calls autotools to build configure script and Makefile.in. 4 | # Generated automatically using bootstrapper 0.2.1 5 | # http://bootstrapper.sourceforge.net/ 6 | # 7 | # Copyright (C) 2002 Anthony Ventimiglia 8 | # 9 | # This bootstrap script is free software; you can redistribute 10 | # it and/or modify it under the terms of the GNU General Public 11 | # License as published by the Free Software Foundation; either 12 | # version 2 of the License, or (at your option) any later version. 13 | # 14 | # 15 | # Calls proper programs to create configure script and Makefile.in files. 16 | # if run with the --clean option, bootstrap removes files it generates. To 17 | # clean all autogenerated files (eg: for cvs imports) first run 18 | # make distclean, then bootstrap --clean 19 | # see bootstrapper(1) for more infor 20 | 21 | 22 | if test x"$1" = x"--help"; then 23 | echo "$0: automatic bootstrapping utility for GNU Autotools" 24 | echo " cleans up old autogenerated files and runs autoconf," 25 | echo " automake and aclocal on local directory" 26 | echo 27 | echo " --clean clean up auto-generated files without" 28 | echo " creating new scripts" 29 | echo 30 | exit 0 31 | fi 32 | 33 | 34 | mkdir -p ac 35 | test -f AUTHORS || touch AUTHORS 36 | test -f COPYING || touch COPYING 37 | test -f ChangeLog || touch ChangeLog 38 | test -f NEWS || touch NEWS 39 | test -f README || cp -f README.md README 40 | 41 | if ! ./preprocess; then 42 | exit 1 43 | fi 44 | 45 | ACLOCAL="aclocal" 46 | ACLOCAL_FILES="aclocal.m4" 47 | ALWAYS_CLEAN="config.status config.log config.cache libtool" 48 | AUTOCONF="autoconf" 49 | AUTOCONF_FILES="configure" 50 | AUTOHEADER="autoheader" 51 | AUTOHEADER_FILES="" 52 | AUTOMAKE="automake --add-missing --copy" 53 | AUTOMAKE_FILES="config.sub stamp-h.in ltmain.sh missing mkinstalldirs install-sh config.guess" 54 | CONFIG_AUX_DIR="." 55 | CONFIG_FILES="stamp-h ltconfig" 56 | CONFIG_HEADER="" 57 | if [ x`uname` = x"Darwin" ]; then 58 | LIBTOOLIZE="glibtoolize --force --copy" 59 | else 60 | LIBTOOLIZE="libtoolize --force --copy" 61 | fi 62 | LIBTOOLIZE_FILES="config.sub ltmain.sh config.guess" 63 | RM="rm" 64 | SUBDIRS="[]" 65 | 66 | 67 | # These are files created by configure, so we'll always clean them 68 | for i in $ALWAYS_CLEAN; do 69 | test -f $i && \ 70 | $RM $i 71 | done 72 | 73 | if test x"$1" = x"--clean"; then 74 | # 75 | #Clean Files left by previous bootstrap run 76 | # 77 | if test -n "$CONFIG_AUX_DIR"; 78 | then CONFIG_AUX_DIR="$CONFIG_AUX_DIR/" 79 | fi 80 | # Clean Libtoolize generated files 81 | for cf in $LIBTOOLIZE_FILES; do 82 | cf="$CONFIG_AUX_DIR$cf" 83 | test -f $cf && \ 84 | $RM $cf 85 | done 86 | #aclocal.m4 created by aclocal 87 | test -f $ACLOCAL_FILES && $RM $ACLOCAL_FILES 88 | #Clean Autoheader Generated files 89 | for cf in $AUTOHEADER_FILES; do 90 | cf=$CONFIG_AUX_DIR$cf 91 | test -f $cf && \ 92 | $RM $cf 93 | done 94 | # remove config header (Usaually config.h) 95 | test -n "$CONFIG_HEADER" && test -f $CONFIG_HEADER && $RM $CONFIG_HEADER 96 | #Clean Automake generated files 97 | for cf in $AUTOMAKE_FILES; do 98 | cf=$CONFIG_AUX_DIR$cf 99 | test -f $cf && \ 100 | $RM $cf 101 | done 102 | for i in $SUBDIRS; do 103 | test -f $i/Makefile.in && \ 104 | $RM $i/Makefile.in 105 | done 106 | #Autoconf generated files 107 | for cf in $AUTOCONF_FILES; do 108 | test -f $cf && \ 109 | $RM $cf 110 | done 111 | for cf in $CONFIG_FILES; do 112 | cf="$CONFIG_AUX_DIR$cf" 113 | test -f $cf && \ 114 | $RM $cf 115 | done 116 | else 117 | $LIBTOOLIZE 118 | $ACLOCAL 119 | $AUTOHEADER 120 | $AUTOMAKE 121 | $AUTOCONF 122 | fi 123 | 124 | 125 | -------------------------------------------------------------------------------- /configure.in: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 2 | 3 | AC_INIT(mpsrc/wavy_kernel.h) 4 | AC_CONFIG_AUX_DIR(ac) 5 | AC_CANONICAL_TARGET 6 | 7 | AM_INIT_AUTOMAKE(jubatus_mpio, 0.4.5) 8 | AC_CONFIG_HEADER(config.h) 9 | 10 | AC_PROG_CC 11 | AC_PROG_CXX 12 | 13 | AC_PROG_LIBTOOL 14 | AM_PROG_AS 15 | AM_PROG_CC_C_O 16 | 17 | AC_SUBST([AM_CXXFLAGS], [-pthread]) 18 | 19 | AC_CACHE_CHECK([for __sync_* atomic operations], kumofs_cv_atomic_ops, [ 20 | AC_TRY_LINK([ 21 | int atomic_sub(int i) { return __sync_sub_and_fetch(&i, 1); } 22 | int atomic_add(int i) { return __sync_add_and_fetch(&i, 1); } 23 | int atomic_cas(int i) { return __sync_bool_compare_and_swap(&i, 0, 1); } 24 | ], [], kumofs_cv_atomic_ops="yes") 25 | ]) 26 | if test "$kumofs_cv_atomic_ops" != "yes"; then 27 | AC_MSG_ERROR([__sync_* atomic operations are not supported. 28 | 29 | Note that gcc < 4.1 is not supported. 30 | 31 | If you are using gcc >= 4.1 and the default target CPU architecture is "i386", try to 32 | add CFLAGS="-march=i686" and CXXFLAGS="-march=i686" options to ./configure as follows: 33 | 34 | $ ./configure CFLAGS="-march=i686" CXXFLAGS="-march=i686" 35 | ]) 36 | fi 37 | 38 | 39 | AC_CHECK_LIB(stdc++, main) 40 | 41 | AC_CHECK_LIB(pthread,pthread_create,, 42 | AC_MSG_ERROR([Can't find pthread library])) 43 | 44 | 45 | case "$target_os" in 46 | solaris*) 47 | AC_CHECK_LIB(socket,accept,, 48 | AC_MSG_ERROR([Can't find libsocket.])) 49 | AC_CHECK_LIB(nsl,inet_ntop,, 50 | AC_MSG_ERROR([Can't find libnsl.])) 51 | AC_CHECK_LIB(sendfile,sendfile,, 52 | AC_MSG_ERROR([Can't find libsendfile.])) 53 | CXXFLAGS="$CXXFLAGS -D_REENTRANT" 54 | CFLAGS="$CFLAGS -D_REENTRANT" 55 | ;; 56 | 57 | linux*) 58 | AC_MSG_CHECKING([if timerfd is enabled]) 59 | AC_ARG_ENABLE(timerfd, 60 | AS_HELP_STRING([--disable-timerfd], 61 | [use POSIX timer instead of timerfd. (compatility for linux < 2.6.25)]) ) 62 | AC_MSG_RESULT($enable_timerfd) 63 | if test "$enable_timerfd" = "no"; then 64 | CXXFLAGS="$CXXFLAGS -DDISABLE_TIMERFD" 65 | CFLAGS="$CFLAGS -DDISABLE_TIMERFD" 66 | AC_CHECK_LIB(rt,timer_create,, 67 | AC_MSG_ERROR([Can't find rt library])) 68 | else 69 | AC_CHECK_HEADER(sys/timerfd.h, [], 70 | AC_MSG_ERROR([sys/timerfd.h is not available. 71 | 72 | You can't use timerfd on this system. 73 | It requires linux >= 2.6.25 and glibc >= 2.8. 74 | Add --disable-timerfd option to use POSIX timer instead of timerfd. 75 | ])) 76 | fi 77 | 78 | AC_MSG_CHECKING([if signalfd is enabled]) 79 | AC_ARG_ENABLE(signalfd, 80 | AS_HELP_STRING([--disable-signalfd], 81 | [do not use signalfd. (compatility for linux < 2.6.22)]) ) 82 | AC_MSG_RESULT($enable_signalfd) 83 | if test "$enable_signalfd" = "no"; then 84 | CXXFLAGS="$CXXFLAGS -DDISABLE_SIGNALFD" 85 | CFLAGS="$CFLAGS -DDISABLE_SIGNALFD" 86 | else 87 | AC_CHECK_HEADER(sys/signalfd.h, [], 88 | AC_MSG_ERROR([sys/signalfd.h is not available. 89 | 90 | You can't use mp::wavy::add_signal on this system. 91 | It requires linux >= 2.6.22 and glibc >= 2.8. 92 | Add --disable-signalfd option to disable mp::wavy::add_signal. 93 | ])) 94 | fi 95 | 96 | ;; 97 | esac 98 | 99 | 100 | AC_MSG_CHECKING([if debug option is enabled]) 101 | AC_ARG_ENABLE(debug, 102 | AS_HELP_STRING([--disable-debug], 103 | [disable assert macros and omit -g option.]) ) 104 | if test "$enable_debug" != "no"; then 105 | CXXFLAGS="$CXXFLAGS -g" 106 | CFLAGS="$CFLAGS -g" 107 | else 108 | CXXFLAGS="$CXXFLAGS -DNDEBUG" 109 | CFLAGS="$CFLAGS -DNDEBUG" 110 | fi 111 | AC_MSG_RESULT($enable_debug) 112 | 113 | AC_OUTPUT([Makefile 114 | jubatus/mp/Makefile 115 | mpsrc/Makefile 116 | test/Makefile]) 117 | 118 | -------------------------------------------------------------------------------- /jubatus/mp/Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 2 | 3 | libjubatus_mpio_includedir = $(includedir)/jubatus/mp 4 | 5 | libjubatus_mpio_include_HEADERS = \ 6 | endian.h \ 7 | exception.h \ 8 | functional.h \ 9 | iocntl.h \ 10 | memory.h \ 11 | object_callback.h \ 12 | object_delete.h \ 13 | pthread.h \ 14 | shared_buffer.h \ 15 | signal.h \ 16 | sparse_array.h \ 17 | stream_buffer.h \ 18 | sync.h \ 19 | tls_set.h \ 20 | unordered.h \ 21 | unordered_map.h \ 22 | unordered_set.h \ 23 | utilize.h \ 24 | wavy.h 25 | 26 | PREP_SOURCE = \ 27 | object_callback.hmpl \ 28 | sparse_array.hmpl \ 29 | sync.hmpl \ 30 | wavy.hmpl 31 | 32 | -------------------------------------------------------------------------------- /jubatus/mp/endian.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio endian 3 | // 4 | // Copyright (C) 2009-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #ifndef MP_ENDIAN_H__ 19 | #define MP_ENDIAN_H__ 20 | #ifdef MP_EXPERIMENTAL 21 | 22 | #include 23 | #include 24 | 25 | namespace mp { 26 | 27 | 28 | #if 0 29 | inline uint16_t htons(uint16_t x) { ::htons(x); } 30 | inline uint16_t ntohs(uint16_t x) { ::ntohs(x); } 31 | inline uint32_t htonl(uint32_t x) { ::htonl(x); } 32 | inline uint32_t ntohl(uint32_t x) { ::ntohl(x); } 33 | #endif 34 | 35 | 36 | #if defined(__BIG_ENDIAN__) || (!defined(__LITTLE_ENDIAN__) && __BYTE_ORDER == __BIG_ENDIAN) 37 | inline uint64_t htonll(uint64_t x) { return x; } 38 | inline uint64_t ntohll(uint64_t x) { return x; } 39 | #else 40 | 41 | #if defined(bswap_64) 42 | inline uint64_t htonll(uint64_t x) { return bswap_64(x); } 43 | inline uint64_t ntohll(uint64_t x) { return bswap_64(x); } 44 | #elif defined(__DARWIN_OSSwapInt64) 45 | inline uint64_t htonll(uint64_t x) { return __DARWIN_OSSwapInt64(x); } 46 | inline uint64_t ntohll(uint64_t x) { return __DARWIN_OSSwapInt64(x); } 47 | #elif defined(_byteswap_uint64) 48 | inline uint64_t htonll(uint64_t x) { return _byteswap_uint64(x); } 49 | inline uint64_t ntohll(uint64_t x) { return _byteswap_uint64(x); } 50 | #else 51 | inline uint64_t htonll(uint64_t x) { 52 | return ((x << 56) & 0xff00000000000000ULL ) | 53 | ((x << 40) & 0x00ff000000000000ULL ) | 54 | ((x << 24) & 0x0000ff0000000000ULL ) | 55 | ((x << 8) & 0x000000ff00000000ULL ) | 56 | ((x >> 8) & 0x00000000ff000000ULL ) | 57 | ((x >> 24) & 0x0000000000ff0000ULL ) | 58 | ((x >> 40) & 0x000000000000ff00ULL ) | 59 | ((x >> 56) & 0x00000000000000ffULL ) ; 60 | } 61 | inline uint64_t ntohll(uint64_t x) { return htonll(x); } 62 | #endif 63 | 64 | #endif 65 | 66 | 67 | } // namespace mp 68 | 69 | #endif /* MP_EXPERIMENTAL */ 70 | #endif /* mp/endian.h */ 71 | 72 | -------------------------------------------------------------------------------- /jubatus/mp/exception.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio exception 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #ifndef MP_EXCEPTION_H__ 19 | #define MP_EXCEPTION_H__ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | namespace mp { 28 | 29 | 30 | struct system_error : std::runtime_error { 31 | static std::string errno_string(int errno_) 32 | { 33 | char buf[512]; 34 | #if defined(__linux__) 35 | char *ret; 36 | ret = strerror_r(errno_, buf, sizeof(buf)-1); 37 | return std::string(ret); 38 | #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined(__SunOS__) 39 | strerror_r(errno_, buf, sizeof(buf)-1); 40 | return std::string(buf); 41 | #else 42 | return std::string(strerror(errno_)); 43 | #endif 44 | } 45 | 46 | system_error(int errno_, const std::string& msg) : 47 | std::runtime_error(msg + ": " + errno_string(errno_)), 48 | code(errno_) { } 49 | 50 | int code; 51 | }; 52 | 53 | 54 | struct event_error : system_error { 55 | event_error(int errno_, const std::string& msg) : 56 | system_error(errno_, msg) {} 57 | }; 58 | 59 | 60 | } // namespace mp 61 | 62 | #endif /* mp/exception.h */ 63 | 64 | -------------------------------------------------------------------------------- /jubatus/mp/functional.h: -------------------------------------------------------------------------------- 1 | // 2 | // mp::functional 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #ifndef MP_FUNCTIONAL_H__ 19 | #define MP_FUNCTIONAL_H__ 20 | 21 | #ifdef MP_FUNCTIONAL_BOOST 22 | #include 23 | namespace mp { 24 | using std::tr1::function; 25 | using std::tr1::bind; 26 | namespace placeholders { 27 | using namespace std::tr1::placeholders; 28 | } 29 | } 30 | #else 31 | #ifdef MP_FUNCTIONAL_BOOST_ORG 32 | #include 33 | #include 34 | namespace mp { 35 | using boost::function; 36 | using boost::bind; 37 | namespace placeholders { } 38 | } 39 | #else 40 | #ifndef MP_FUNCTIONAL_STANDARD 41 | #include 42 | namespace mp { 43 | using std::tr1::function; 44 | using std::tr1::bind; 45 | namespace placeholders { 46 | using namespace std::tr1::placeholders; 47 | } 48 | } 49 | #else 50 | #include 51 | namespace mp { 52 | using std::function; 53 | using std::bind; 54 | namespace placeholders { 55 | using namespace std::placeholders; 56 | } 57 | } 58 | #endif 59 | #endif 60 | #endif 61 | 62 | #endif /* mp/functional.h */ 63 | 64 | -------------------------------------------------------------------------------- /jubatus/mp/iocntl.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio iocntl 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #ifndef MP_IOCNTL_H__ 19 | #define MP_IOCNTL_H__ 20 | #ifdef MP_EXPERIMENTAL 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace mp { 32 | 33 | 34 | inline bool set_nonblock(int fd) 35 | { 36 | return ::fcntl(fd, F_SETFL, O_NONBLOCK) >= 0; 37 | } 38 | 39 | inline bool set_tcp_nodelay(int fd) 40 | { 41 | int on = 1; 42 | return ::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) >= 0; 43 | } 44 | 45 | inline bool set_linger(int fd, bool sync, bool wait) 46 | { 47 | struct linger opt = {(sync ? 1 : 0), (wait ? 1 : 0)}; 48 | return ::setsockopt(fd, SOL_SOCKET, SO_LINGER, (void *)&opt, sizeof(opt)) >= 0; 49 | } 50 | 51 | inline bool set_reuse_addr(int fd) 52 | { 53 | int on = 1; 54 | return ::setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) >= 0; 55 | } 56 | 57 | inline bool set_recv_timeout(int fd, struct timeval tv) 58 | { 59 | return ::setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) >= 0; 60 | } 61 | 62 | inline bool set_send_timeout(int fd, struct timeval tv) 63 | { 64 | return ::setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) >= 0; 65 | } 66 | 67 | inline bool set_recv_timeout(int fd, double sec) 68 | { 69 | if(sec <= 0) { return true; } 70 | struct timeval tv = {sec, sec*1e6}; 71 | return set_recv_timeout(tv); 72 | } 73 | 74 | inline bool set_send_timeout(int fd, double sec) 75 | { 76 | if(sec <= 0) { return true; } 77 | struct timeval tv = {sec, sec*1e6}; 78 | return set_send_timeout(tv); 79 | } 80 | 81 | inline bool isEAGAIN(int err = errno) 82 | { 83 | return err == EAGAIN; 84 | } 85 | 86 | inline bool isEINTR(int err = errno) 87 | { 88 | return err == EINVAL; 89 | } 90 | 91 | // #define isEAGAIN mp::isEAGAIN() 92 | // #define isEINTR mp::isEINTR() 93 | 94 | 95 | } // namespace mp 96 | 97 | #endif /* MP_EXPERIMENTAL */ 98 | #endif /* mp/iocntl.h */ 99 | 100 | -------------------------------------------------------------------------------- /jubatus/mp/memory.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio memory 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #ifndef MP_MEMORY_H__ 19 | #define MP_MEMORY_H__ 20 | 21 | #ifdef MP_MEMORY_BOOST 22 | #include 23 | namespace mp { 24 | using std::tr1::shared_ptr; 25 | using std::tr1::wak_ptr; 26 | //using std::tr2::scoped_ptr; 27 | using std::tr1::static_pointer_cast; 28 | using std::tr1::dynamic_pointer_cast; 29 | using std::tr1::enable_shared_from_this; 30 | } 31 | #else 32 | #ifdef MP_MEMORY_BOOST_ORG 33 | #include 34 | #include 35 | #include 36 | //#include 37 | namespace mp { 38 | using boost::shared_ptr; 39 | using boost::weak_ptr; 40 | //using boost::scoped_ptr; 41 | using boost::static_pointer_cast; 42 | using boost::dynamic_pointer_cast; 43 | using boost::enable_shared_from_this; 44 | } 45 | #else 46 | #ifndef MP_MEMORY_STANDARD 47 | #include 48 | namespace mp { 49 | using std::tr1::shared_ptr; 50 | using std::tr1::weak_ptr; 51 | //using std::tr2::scoped_ptr; 52 | using std::tr1::static_pointer_cast; 53 | using std::tr1::dynamic_pointer_cast; 54 | using std::tr1::enable_shared_from_this; 55 | } 56 | #else 57 | #include 58 | namespace mp { 59 | using std::shared_ptr; 60 | using std::weak_ptr; 61 | //using std::scoped_ptr; 62 | using std::static_pointer_cast; 63 | using std::dynamic_pointer_cast; 64 | using std::enable_shared_from_this; 65 | } 66 | #endif 67 | #endif 68 | #endif 69 | 70 | #endif /* mp/memory.h */ 71 | 72 | -------------------------------------------------------------------------------- /jubatus/mp/object_callback.hmpl: -------------------------------------------------------------------------------- 1 | // 2 | // mpio object_callback 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | #ifndef MP_OBJECT_CALLBACK_H__ 20 | #define MP_OBJECT_CALLBACK_H__ 21 | 22 | #include "jubatus/mp/memory.h" 23 | #include "jubatus/mp/object_delete.h" 24 | 25 | namespace mp { 26 | 27 | 28 | template 29 | struct object_callback; 30 | 31 | template 32 | struct object_callback 33 | { 34 | template 35 | static R mem_fun(void* obj) 36 | { 37 | return (reinterpret_cast(obj)->*MemFun)(); 38 | } 39 | 40 | template 41 | static R const_mem_fun(const void* obj) 42 | { 43 | return (reinterpret_cast(obj)->*MemFun)(); 44 | } 45 | 46 | template 47 | static R shared_fun(shared_ptr obj) 48 | { 49 | return (obj.get()->*MemFun)(); 50 | } 51 | }; 52 | 53 | %varlen_each do |gen| 54 | template 55 | struct object_callback 56 | { 57 | template 58 | static R mem_fun(void* obj, [%gen.args%]) 59 | { 60 | return (reinterpret_cast(obj)->*MemFun)([%gen.params%]); 61 | } 62 | 63 | template 64 | static R const_mem_fun(const void* obj, [%gen.args%]) 65 | { 66 | return (reinterpret_cast(obj)->*MemFun)([%gen.params%]); 67 | } 68 | 69 | template 70 | static R shared_fun(shared_ptr obj, [%gen.args%]) 71 | { 72 | return (obj.get()->*MemFun)([%gen.params%]); 73 | } 74 | }; 75 | 76 | %end 77 | 78 | 79 | } // namespace mp 80 | 81 | #endif /* mp/object_callback.h */ 82 | 83 | %# vim: filetype=mplex 84 | -------------------------------------------------------------------------------- /jubatus/mp/object_delete.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio object_delete 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #ifndef MP_OBJECT_DELETE_H__ 19 | #define MP_OBJECT_DELETE_H__ 20 | 21 | namespace mp { 22 | 23 | 24 | template 25 | static void object_delete(void* obj) 26 | { 27 | delete reinterpret_cast(obj); 28 | } 29 | 30 | 31 | template 32 | static void object_destructor(void* obj) 33 | { 34 | reinterpret_cast(obj)->~T(); 35 | } 36 | 37 | 38 | } // namespace mp 39 | 40 | #endif /* mp/object_delete.h */ 41 | 42 | -------------------------------------------------------------------------------- /jubatus/mp/pthread.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio pthread 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | #ifndef MP_PTHREAD_H__ 20 | #define MP_PTHREAD_H__ 21 | 22 | #include "jubatus/mp/exception.h" 23 | #include "jubatus/mp/functional.h" 24 | #include 25 | #include 26 | 27 | namespace mp { 28 | 29 | 30 | struct pthread_error : system_error { 31 | pthread_error(int errno_, const std::string& msg) : 32 | system_error(errno_, msg) {} 33 | }; 34 | 35 | 36 | struct pthread_thread { 37 | private: 38 | typedef function function_t; 39 | 40 | public: 41 | void create(void* (*func)(void*), void* user) 42 | { 43 | int err = pthread_create(&m_thread, NULL, 44 | func, user); 45 | if(err) { throw pthread_error(err, "failed to create thread"); } 46 | } 47 | 48 | void run(function_t func) 49 | { 50 | std::auto_ptr f(new function_t(func)); 51 | create(&trampoline, reinterpret_cast(f.get())); 52 | f.release(); 53 | } 54 | 55 | void detach() 56 | { 57 | int err = pthread_detach(m_thread); 58 | if(err) { throw pthread_error(err, "failed to detach thread"); } 59 | } 60 | 61 | void* join() 62 | { 63 | void* ret; 64 | int err = pthread_join(m_thread, &ret); 65 | if(err) { throw pthread_error(err, "failed to join thread"); } 66 | return ret; 67 | } 68 | 69 | void cancel() 70 | { 71 | pthread_cancel(m_thread); 72 | } 73 | 74 | 75 | bool operator== (const pthread_thread& other) const 76 | { 77 | return pthread_equal(m_thread, other.m_thread); 78 | } 79 | 80 | bool operator!= (const pthread_thread& other) const 81 | { 82 | return !(*this == other); 83 | } 84 | 85 | 86 | static void exit(void* retval = NULL) 87 | { 88 | pthread_exit(retval); 89 | } 90 | 91 | private: 92 | pthread_t m_thread; 93 | 94 | static void* trampoline(void* user); 95 | }; 96 | 97 | 98 | template 99 | struct pthread_thread_impl : public pthread_thread { 100 | pthread_thread_impl() : pthread_thread(this) { } 101 | virtual ~pthread_thread_impl() { } 102 | }; 103 | 104 | 105 | class pthread_mutex { 106 | public: 107 | pthread_mutex(const pthread_mutexattr_t *attr = NULL) 108 | { 109 | pthread_mutex_init(&m_mutex, attr); 110 | } 111 | 112 | pthread_mutex(int kind) 113 | { 114 | pthread_mutexattr_t attr; 115 | pthread_mutexattr_init(&attr); 116 | pthread_mutexattr_settype(&attr, kind); 117 | pthread_mutex_init(&m_mutex, &attr); 118 | } 119 | 120 | ~pthread_mutex() 121 | { 122 | pthread_mutex_destroy(&m_mutex); 123 | } 124 | 125 | public: 126 | void lock() 127 | { 128 | int err = pthread_mutex_lock(&m_mutex); 129 | if(err != 0) { throw pthread_error(-err, "failed to lock pthread mutex"); } 130 | } 131 | 132 | bool trylock() 133 | { 134 | int err = pthread_mutex_trylock(&m_mutex); 135 | if(err != 0) { 136 | if(err == EBUSY) { return false; } 137 | throw pthread_error(-err, "failed to trylock pthread mutex"); 138 | } 139 | return true; 140 | } 141 | 142 | void unlock() 143 | { 144 | int err = pthread_mutex_unlock(&m_mutex); 145 | if(err != 0) { throw pthread_error(-err, "failed to unlock pthread mutex"); } 146 | } 147 | 148 | public: 149 | pthread_mutex_t* get() { return &m_mutex; } 150 | private: 151 | pthread_mutex_t m_mutex; 152 | private: 153 | pthread_mutex(const pthread_mutex&); 154 | }; 155 | 156 | class pthread_recursive_mutex: public pthread_mutex { 157 | public: 158 | pthread_recursive_mutex(): pthread_mutex(PTHREAD_MUTEX_RECURSIVE) {} 159 | }; 160 | 161 | class pthread_rwlock { 162 | public: 163 | pthread_rwlock(const pthread_rwlockattr_t *attr = NULL) 164 | { 165 | pthread_rwlock_init(&m_mutex, attr); 166 | } 167 | 168 | // FIXME kind 169 | //pthread_rwlock(int kind) 170 | //{ 171 | // pthread_rwlockattr_t attr; 172 | // pthread_rwlockattr_init(&attr); 173 | // pthread_rwlockattr_settype(&attr, kind); 174 | // pthread_rwlock_init(&m_mutex, &attr); 175 | //} 176 | 177 | ~pthread_rwlock() 178 | { 179 | pthread_rwlock_destroy(&m_mutex); 180 | } 181 | 182 | public: 183 | void rdlock() 184 | { 185 | int err = pthread_rwlock_rdlock(&m_mutex); 186 | if(err != 0) { throw pthread_error(-err, "failed to read lock pthread rwlock"); } 187 | } 188 | 189 | bool tryrdlock() 190 | { 191 | int err = pthread_rwlock_tryrdlock(&m_mutex); 192 | if(err != 0) { 193 | if(err == EBUSY) { return false; } 194 | throw pthread_error(-err, "failed to read trylock pthread rwlock"); 195 | } 196 | return true; 197 | } 198 | 199 | void wrlock() 200 | { 201 | int err = pthread_rwlock_wrlock(&m_mutex); 202 | if(err != 0) { throw pthread_error(-err, "failed to write lock pthread rwlock"); } 203 | } 204 | 205 | bool trywrlock() 206 | { 207 | int err = pthread_rwlock_trywrlock(&m_mutex); 208 | if(err != 0) { 209 | if(err == EBUSY) { return false; } 210 | throw pthread_error(-err, "failed to write trylock pthread rwlock"); 211 | } 212 | return true; 213 | } 214 | 215 | void unlock() 216 | { 217 | int err = pthread_rwlock_unlock(&m_mutex); 218 | if(err != 0) { throw pthread_error(-err, "failed to unlock pthread rwlock"); } 219 | } 220 | 221 | public: 222 | pthread_rwlock_t* get() { return &m_mutex; } 223 | private: 224 | pthread_rwlock_t m_mutex; 225 | private: 226 | pthread_rwlock(const pthread_rwlock&); 227 | }; 228 | 229 | 230 | class pthread_scoped_lock { 231 | public: 232 | pthread_scoped_lock() : m_mutex(NULL) { } 233 | 234 | pthread_scoped_lock(pthread_mutex& mutex) : m_mutex(NULL) 235 | { 236 | mutex.lock(); 237 | m_mutex = &mutex; 238 | } 239 | 240 | ~pthread_scoped_lock() 241 | { 242 | if(m_mutex) { 243 | m_mutex->unlock(); 244 | } 245 | } 246 | 247 | public: 248 | void unlock() 249 | { 250 | if(m_mutex) { 251 | m_mutex->unlock(); 252 | m_mutex = NULL; 253 | } 254 | } 255 | 256 | void relock(pthread_mutex& mutex) 257 | { 258 | unlock(); 259 | mutex.lock(); 260 | m_mutex = &mutex; 261 | } 262 | 263 | bool owns() const 264 | { 265 | return m_mutex != NULL; 266 | } 267 | 268 | private: 269 | pthread_mutex* m_mutex; 270 | private: 271 | pthread_scoped_lock(const pthread_scoped_lock&); 272 | }; 273 | 274 | 275 | class pthread_scoped_rdlock { 276 | public: 277 | pthread_scoped_rdlock() : m_mutex(NULL) { } 278 | 279 | pthread_scoped_rdlock(pthread_rwlock& mutex) : m_mutex(NULL) 280 | { 281 | mutex.rdlock(); 282 | m_mutex = &mutex; 283 | } 284 | 285 | ~pthread_scoped_rdlock() 286 | { 287 | if(m_mutex) { 288 | m_mutex->unlock(); 289 | } 290 | } 291 | 292 | public: 293 | void unlock() 294 | { 295 | if(m_mutex) { 296 | m_mutex->unlock(); 297 | m_mutex = NULL; 298 | } 299 | } 300 | 301 | void relock(pthread_rwlock& mutex) 302 | { 303 | unlock(); 304 | mutex.rdlock(); 305 | m_mutex = &mutex; 306 | } 307 | 308 | bool owns() const 309 | { 310 | return m_mutex != NULL; 311 | } 312 | 313 | private: 314 | pthread_rwlock* m_mutex; 315 | private: 316 | pthread_scoped_rdlock(const pthread_scoped_rdlock&); 317 | }; 318 | 319 | 320 | class pthread_scoped_wrlock { 321 | public: 322 | pthread_scoped_wrlock() : m_mutex(NULL) { } 323 | 324 | pthread_scoped_wrlock(pthread_rwlock& mutex) : m_mutex(NULL) 325 | { 326 | mutex.wrlock(); 327 | m_mutex = &mutex; 328 | } 329 | 330 | ~pthread_scoped_wrlock() 331 | { 332 | if(m_mutex) { 333 | m_mutex->unlock(); 334 | } 335 | } 336 | 337 | public: 338 | void unlock() 339 | { 340 | if(m_mutex) { 341 | m_mutex->unlock(); 342 | m_mutex = NULL; 343 | } 344 | } 345 | 346 | void relock(pthread_rwlock& mutex) 347 | { 348 | unlock(); 349 | mutex.wrlock(); 350 | m_mutex = &mutex; 351 | } 352 | 353 | bool owns() const 354 | { 355 | return m_mutex != NULL; 356 | } 357 | 358 | private: 359 | pthread_rwlock* m_mutex; 360 | private: 361 | pthread_scoped_wrlock(const pthread_scoped_wrlock&); 362 | }; 363 | 364 | 365 | class pthread_cond { 366 | public: 367 | pthread_cond(const pthread_condattr_t *attr = NULL) 368 | { 369 | pthread_cond_init(&m_cond, attr); 370 | } 371 | 372 | ~pthread_cond() 373 | { 374 | pthread_cond_destroy(&m_cond); 375 | } 376 | 377 | public: 378 | void signal() 379 | { 380 | int err = pthread_cond_signal(&m_cond); 381 | if(err != 0) { throw pthread_error(-err, "failed to signal pthread cond"); } 382 | } 383 | 384 | void broadcast() 385 | { 386 | int err = pthread_cond_broadcast(&m_cond); 387 | if(err != 0) { throw pthread_error(-err, "failed to broadcast pthread cond"); } 388 | } 389 | 390 | void wait(pthread_mutex& mutex) 391 | { 392 | int err = pthread_cond_wait(&m_cond, mutex.get()); 393 | if(err != 0) { throw pthread_error(-err, "failed to wait pthread cond"); } 394 | } 395 | 396 | bool timedwait(pthread_mutex& mutex, const struct timespec *abstime) 397 | { 398 | int err = pthread_cond_timedwait(&m_cond, mutex.get(), abstime); 399 | if(err != 0) { 400 | if(err == ETIMEDOUT) { return false; } 401 | throw pthread_error(-err, "failed to timedwait pthread cond"); 402 | } 403 | return true; 404 | } 405 | 406 | public: 407 | pthread_cond_t* get() { return &m_cond; } 408 | private: 409 | pthread_cond_t m_cond; 410 | private: 411 | pthread_cond(const pthread_cond&); 412 | }; 413 | 414 | 415 | } // namespace mp 416 | 417 | 418 | #include 419 | #include 420 | #ifndef MP_NO_CXX_ABI_H 421 | #include 422 | #endif 423 | 424 | namespace mp { 425 | 426 | 427 | inline void* pthread_thread::trampoline(void* user) 428 | try { 429 | std::auto_ptr f(reinterpret_cast(user)); 430 | (*f)(); 431 | return NULL; 432 | 433 | } catch (std::exception& e) { 434 | try { 435 | #ifndef MP_NO_CXX_ABI_H 436 | int status; 437 | std::cerr 438 | << "thread terminated with throwing an instance of '" 439 | << abi::__cxa_demangle(typeid(e).name(), 0, 0, &status) 440 | << "'\n" " what(): " << e.what() << std::endl; 441 | #else 442 | std::cerr 443 | << "thread terminated with throwing an instance of '" 444 | << typeid(e).name() 445 | << "'\n" " what(): " << e.what() << std::endl; 446 | #endif 447 | } catch (...) {} 448 | throw; 449 | 450 | } catch (...) { 451 | try { 452 | std::cerr << "thread terminated with throwing an unknown object" << std::endl; 453 | } catch (...) {} 454 | throw; 455 | } 456 | 457 | 458 | } // namespace mp 459 | 460 | #endif /* mp/pthread.h */ 461 | 462 | -------------------------------------------------------------------------------- /jubatus/mp/shared_buffer.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio shared_buffer 3 | // 4 | // Copyright (C) 2009-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #ifndef MP_SHARED_BUFFER_H__ 19 | #define MP_SHARED_BUFFER_H__ 20 | 21 | #include 22 | #include 23 | 24 | #ifndef MP_SHARED_BUFFER_INITIAL_BUFFER_SIZE 25 | #define MP_SHARED_BUFFER_INITIAL_BUFFER_SIZE 8*1024 26 | #endif 27 | 28 | namespace mp { 29 | 30 | 31 | /** 32 | * shared_buffer: 33 | * +-----------------------------+ 34 | * | filled space | unused space | 35 | * +-----------------------------+ 36 | * ^ buffer() 37 | * 38 | * +--------------+ 39 | * buffer_capacity() 40 | * 41 | * reserve_buffer() +-> 42 | * 43 | * +----+ 44 | * holded 45 | * +------+ 46 | * holded (not to be freed) 47 | * 48 | * +-> hold() 49 | * +-> skip() 50 | * 51 | */ 52 | 53 | class shared_buffer { 54 | public: 55 | shared_buffer(size_t init_size = MP_SHARED_BUFFER_INITIAL_BUFFER_SIZE); 56 | ~shared_buffer(); 57 | 58 | public: 59 | class ref { 60 | public: 61 | ref(); 62 | ref(const ref& o); 63 | ~ref(); 64 | void clear(); 65 | void swap(ref& x); 66 | private: 67 | void* m; 68 | private: 69 | ref(void* p); 70 | void reset(void* p); 71 | friend class ref; 72 | }; 73 | 74 | void reserve_buffer(size_t len, 75 | size_t init_size = MP_SHARED_BUFFER_INITIAL_BUFFER_SIZE); 76 | 77 | void* buffer(); 78 | size_t buffer_capacity() const; 79 | 80 | ref hold(size_t len); 81 | void skip(size_t len); 82 | 83 | private: 84 | char* m_buffer; 85 | size_t m_used; 86 | size_t m_free; 87 | 88 | private: 89 | void expand_buffer(size_t len, size_t init_size); 90 | 91 | typedef volatile unsigned int count_t; 92 | static void init_count(void* d); 93 | static void decr_count(void* d); 94 | static void incr_count(void* d); 95 | static count_t get_count(void* d); 96 | 97 | private: 98 | shared_buffer(const shared_buffer&); 99 | }; 100 | 101 | 102 | 103 | inline void shared_buffer::init_count(void* d) 104 | { 105 | *(volatile count_t*)d = 1; 106 | } 107 | 108 | inline void shared_buffer::decr_count(void* d) 109 | { 110 | //if(--*(count_t*)d == 0) { 111 | if(__sync_sub_and_fetch((count_t*)d, 1) == 0) { 112 | ::free(d); 113 | } 114 | } 115 | 116 | inline void shared_buffer::incr_count(void* d) 117 | { 118 | //++*(count_t*)d; 119 | __sync_add_and_fetch((count_t*)d, 1); 120 | } 121 | 122 | inline shared_buffer::count_t shared_buffer::get_count(void* d) 123 | { 124 | return *(count_t*)d; 125 | } 126 | 127 | 128 | inline shared_buffer::ref::ref() : m(NULL) { } 129 | 130 | inline shared_buffer::ref::ref(void* p) : 131 | m(p) 132 | { 133 | incr_count(m); 134 | } 135 | 136 | inline shared_buffer::ref::ref(const ref& o) : 137 | m(o.m) 138 | { 139 | incr_count(m); 140 | } 141 | 142 | inline void shared_buffer::ref::clear() 143 | { 144 | if(m) { 145 | decr_count(m); 146 | m = NULL; 147 | } 148 | } 149 | 150 | inline shared_buffer::ref::~ref() 151 | { 152 | clear(); 153 | } 154 | 155 | inline void shared_buffer::ref::reset(void* p) 156 | { 157 | clear(); 158 | m = p; 159 | incr_count(m); 160 | } 161 | 162 | inline void shared_buffer::ref::swap(ref& x) 163 | { 164 | void* tmp = m; 165 | m = x.m; 166 | x.m = tmp; 167 | } 168 | 169 | 170 | inline shared_buffer::shared_buffer(size_t init_size) 171 | { 172 | const size_t initsz = std::max(init_size, sizeof(count_t)); 173 | m_buffer = (char*)::malloc(initsz); 174 | if(m_buffer == NULL) { throw std::bad_alloc(); } 175 | 176 | init_count(m_buffer); 177 | m_used = sizeof(count_t); 178 | m_free = initsz - m_used; 179 | } 180 | 181 | inline shared_buffer::~shared_buffer() 182 | { 183 | decr_count(m_buffer); 184 | } 185 | 186 | inline void* shared_buffer::buffer() 187 | { 188 | return m_buffer + m_used; 189 | } 190 | 191 | inline size_t shared_buffer::buffer_capacity() const 192 | { 193 | return m_free; 194 | } 195 | 196 | inline void shared_buffer::reserve_buffer(size_t len, size_t init_size) 197 | { 198 | if(get_count(m_buffer) == 1) { 199 | // rewind buffer 200 | m_free += m_used - sizeof(count_t); 201 | m_used = sizeof(count_t); 202 | } 203 | if(m_free < len) { 204 | expand_buffer(len, init_size); 205 | } 206 | } 207 | 208 | inline ref shared_buffer::hold(size_t len) 209 | { 210 | if(m_free < len) { len = m_free; } 211 | m_used += len; 212 | m_free -= len; 213 | return ref(m_buffer); 214 | } 215 | 216 | inline void shared_buffer::skip(size_t len) 217 | { 218 | if(m_free < len) { len = m_free; } 219 | m_used += len; 220 | m_free -= len; 221 | } 222 | 223 | inline void shared_buffer::expand_buffer(size_t len, size_t init_size) 224 | { 225 | if(m_used == sizeof(count_t) && get_count(m_buffer) == 1) { 226 | size_t next_size = (m_used + m_free) * 2; 227 | while(next_size < len + m_used) { next_size *= 2; } 228 | 229 | char* tmp = (char*)::realloc(m_buffer, next_size); 230 | if(!tmp) { throw std::bad_alloc(); } 231 | 232 | m_buffer = tmp; 233 | m_free = next_size - m_used; 234 | 235 | } else { 236 | const size_t initsz = std::max(init_size, sizeof(count_t)); 237 | 238 | size_t next_size = initsz; // include sizeof(count_t) 239 | while(next_size < len + sizeof(count_t)) { next_size *= 2; } 240 | 241 | char* tmp = (char*)::malloc(next_size); 242 | if(!tmp) { throw std::bad_alloc(); } 243 | init_count(tmp); 244 | 245 | decr_count(m_buffer); 246 | 247 | m_buffer = tmp; 248 | m_used = sizeof(count_t); 249 | m_free = next_size - m_used; 250 | } 251 | } 252 | 253 | 254 | } // namespace mp 255 | 256 | #endif /* mp/shared_buffer.h */ 257 | 258 | -------------------------------------------------------------------------------- /jubatus/mp/signal.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio signal 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | #ifndef MP_SIGNAL_H__ 20 | #define MP_SIGNAL_H__ 21 | 22 | #include "jubatus/mp/exception.h" 23 | #include "jubatus/mp/pthread.h" 24 | #include 25 | 26 | namespace mp { 27 | 28 | 29 | class sigset { 30 | public: 31 | sigset(const sigset_t& set) : 32 | m_set(set) { } 33 | 34 | sigset() 35 | { set_empty(); } 36 | 37 | sigset& add(int signo) 38 | { sigaddset(&m_set, signo); return* this; } 39 | 40 | sigset& del(int signo) 41 | { sigdelset(&m_set, signo); return* this; } 42 | 43 | sigset& set_empty() 44 | { sigemptyset(&m_set); return* this; } 45 | 46 | sigset& set_fill() 47 | { sigfillset(&m_set); return* this; } 48 | 49 | sigset_t* get() 50 | { 51 | return &m_set; 52 | } 53 | 54 | const sigset_t* get() const 55 | { 56 | return &m_set; 57 | } 58 | 59 | private: 60 | sigset_t m_set; 61 | }; 62 | 63 | 64 | class scoped_sigprocmask { 65 | public: 66 | scoped_sigprocmask(const sigset& set) : m_set(set) 67 | { 68 | if(sigprocmask(SIG_BLOCK, m_set.get(), NULL) < 0) { 69 | throw system_error(errno, "failed to set sigprocmask"); 70 | } 71 | } 72 | 73 | scoped_sigprocmask(const sigset_t& set) : m_set(set) 74 | { 75 | if(sigprocmask(SIG_BLOCK, m_set.get(), NULL) < 0) { 76 | throw system_error(errno, "failed to set sigprocmask"); 77 | } 78 | } 79 | 80 | ~scoped_sigprocmask() 81 | { 82 | sigprocmask(SIG_UNBLOCK, m_set.get(), NULL); 83 | } 84 | 85 | const sigset& get_sigset() const { return m_set; } 86 | 87 | private: 88 | sigset m_set; 89 | 90 | private: 91 | scoped_sigprocmask(); 92 | scoped_sigprocmask(const scoped_sigprocmask&); 93 | }; 94 | 95 | 96 | class scoped_signal { 97 | public: 98 | scoped_signal(int signo, void (*handler)(int)) : 99 | m_signo(signo) 100 | { 101 | struct sigaction act; 102 | memset(&act, 0, sizeof(act)); 103 | act.sa_handler = handler; 104 | sigemptyset(&act.sa_mask); 105 | act.sa_flags = SA_RESTART; 106 | if(sigaction(m_signo, &act, &m_save) < 0) { 107 | throw system_error(errno, "failed to set signal handler"); 108 | } 109 | } 110 | 111 | ~scoped_signal() 112 | { 113 | sigaction(m_signo, &m_save, NULL); 114 | } 115 | 116 | //FIXME 117 | //scoped_signal(int signo, function func); 118 | 119 | private: 120 | int m_signo; 121 | struct sigaction m_save; 122 | 123 | private: 124 | scoped_signal(); 125 | scoped_signal(const scoped_signal&); 126 | }; 127 | 128 | 129 | class pthread_signal : public pthread_thread { 130 | public: 131 | typedef function handler_t; 132 | 133 | pthread_signal(int signo, handler_t handler) : 134 | m_signal(signo, SIG_IGN), 135 | m_sigmask(sigset().add(signo)) 136 | { 137 | run(mp::bind(&pthread_signal::thread_main, signo, handler)); 138 | } 139 | 140 | ~pthread_signal() { } 141 | 142 | public: 143 | static void thread_main(int signo, handler_t handler) 144 | { 145 | sigset set; 146 | set.add(signo); 147 | while(true) { 148 | if(sigwait(set.get(), &signo) != 0) { 149 | signo = -1; 150 | } 151 | if(!handler()) { 152 | return; 153 | } 154 | } 155 | } 156 | 157 | private: 158 | scoped_signal m_signal; 159 | scoped_sigprocmask m_sigmask; 160 | 161 | private: 162 | pthread_signal(); 163 | pthread_signal(const pthread_signal&); 164 | }; 165 | 166 | 167 | } // namespace mp 168 | 169 | #endif /* mp/signal.h */ 170 | 171 | -------------------------------------------------------------------------------- /jubatus/mp/sparse_array.hmpl: -------------------------------------------------------------------------------- 1 | // 2 | // mp::sparse_array 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #ifndef MP_SPARSE_ARRAY_H__ 19 | #define MP_SPARSE_ARRAY_H__ 20 | 21 | #include 22 | #include 23 | 24 | namespace mp { 25 | 26 | 27 | template 28 | class sparse_array { 29 | public: 30 | typedef size_t size_type; 31 | 32 | sparse_array(); 33 | ~sparse_array(); 34 | 35 | //! Set instance of T into index. 36 | inline T& set(size_type index); 37 | %varlen_each do |gen| 38 | template <[%gen.template%]> 39 | inline T& set(size_type index, [%gen.args%]); 40 | %end 41 | 42 | //! Reset index. 43 | inline void reset(size_type index); 44 | 45 | //! Get the data of index. 46 | inline T& data(size_type index); 47 | inline const T& data(size_type index) const; 48 | 49 | //! Get the data of index. 50 | inline T* get(size_type index); 51 | inline const T* get(size_type index) const; 52 | 53 | //! Return true if index is set otherwise false. 54 | inline bool test(size_type index) const; 55 | 56 | inline size_type capacity() const; 57 | 58 | private: 59 | static const size_t EXTEND_ARRAY_SIZE = 64; 60 | 61 | struct item_t { 62 | bool enable; 63 | char data[sizeof(T)]; 64 | }; 65 | 66 | typedef std::vector base_array_t; 67 | base_array_t base_array; 68 | 69 | private: 70 | inline void* set_impl(size_type index); 71 | inline void revert(size_type index); 72 | inline void extend_array(); 73 | inline item_t& item_of(size_type index); 74 | inline const item_t& item_of(size_type index) const; 75 | }; 76 | 77 | 78 | template 79 | sparse_array::sparse_array() 80 | { 81 | extend_array(); 82 | } 83 | 84 | template 85 | sparse_array::~sparse_array() 86 | { 87 | for(typename base_array_t::iterator it(base_array.begin()), it_end(base_array.end()); 88 | it != it_end; 89 | ++it ) { 90 | for(item_t *p(*it), *p_end(p+EXTEND_ARRAY_SIZE); p != p_end; ++p) { 91 | if(p->enable) { 92 | reinterpret_cast(p->data)->~T(); 93 | } 94 | } 95 | std::free(*it); 96 | } 97 | } 98 | 99 | template 100 | T& sparse_array::set(size_type index) 101 | try { 102 | return *(new (set_impl(index)) T()); 103 | } catch (...) { 104 | revert(index); 105 | throw; 106 | } 107 | %varlen_each do |gen| 108 | template 109 | template <[%gen.template%]> 110 | T& sparse_array::set(size_type index, [%gen.args%]) 111 | try { 112 | return *(new (set_impl(index)) T([%gen.params%])); 113 | } catch (...) { 114 | revert(index); 115 | throw; 116 | } 117 | %end 118 | 119 | template 120 | void sparse_array::reset(size_type index) 121 | { 122 | item_t& item(item_of(index)); 123 | item.enable = false; 124 | reinterpret_cast(item.data)->~T(); 125 | } 126 | 127 | template 128 | T& sparse_array::data(size_type index) 129 | { 130 | return *reinterpret_cast(item_of(index).data); 131 | } 132 | 133 | template 134 | const T& sparse_array::data(size_type index) const 135 | { 136 | return *reinterpret_cast(item_of(index).data); 137 | } 138 | 139 | template 140 | T* sparse_array::get(size_type index) 141 | { 142 | if( base_array.size() * EXTEND_ARRAY_SIZE > index ) { 143 | item_t& item(item_of(index)); 144 | if( item.enable ) { 145 | return reinterpret_cast(item.data); 146 | } 147 | } 148 | return NULL; 149 | } 150 | 151 | template 152 | const T* sparse_array::get(size_type index) const 153 | { 154 | if( base_array.size() * EXTEND_ARRAY_SIZE > index ) { 155 | item_t& item(item_of(index)); 156 | if( item.enable ) { 157 | return reinterpret_cast(item.data); 158 | } 159 | } 160 | return NULL; 161 | } 162 | 163 | template 164 | bool sparse_array::test(size_type index) const 165 | { 166 | return base_array.size() * EXTEND_ARRAY_SIZE > index && 167 | item_of(index).enable; 168 | } 169 | 170 | template 171 | typename sparse_array::size_type sparse_array::capacity() const 172 | { 173 | return base_array.size() * EXTEND_ARRAY_SIZE; 174 | } 175 | 176 | template 177 | void* sparse_array::set_impl(size_type index) 178 | { 179 | while( base_array.size() <= index / EXTEND_ARRAY_SIZE ) { 180 | extend_array(); 181 | } 182 | item_t& item(item_of(index)); 183 | if( item.enable ) { 184 | reinterpret_cast(item.data)->~T(); 185 | } else { 186 | item.enable = true; 187 | } 188 | return item.data; 189 | } 190 | 191 | template 192 | void sparse_array::revert(size_type index) 193 | { 194 | item_of(index).enable = false; 195 | } 196 | 197 | template 198 | void sparse_array::extend_array() 199 | { 200 | item_t* ex = (item_t*)std::calloc(EXTEND_ARRAY_SIZE, sizeof(item_t)); 201 | if(!ex) { throw std::bad_alloc(); } 202 | base_array.push_back(ex); 203 | } 204 | 205 | template 206 | typename sparse_array::item_t& sparse_array::item_of(size_type index) 207 | { 208 | return base_array[index / EXTEND_ARRAY_SIZE][index % EXTEND_ARRAY_SIZE]; 209 | } 210 | 211 | template 212 | const typename sparse_array::item_t& sparse_array::item_of(size_type index) const 213 | { 214 | return base_array[index / EXTEND_ARRAY_SIZE][index % EXTEND_ARRAY_SIZE]; 215 | } 216 | 217 | 218 | } // namespace mp 219 | 220 | #endif /* mp/sparse_array.h */ 221 | 222 | %# vim: filetype=mplex 223 | -------------------------------------------------------------------------------- /jubatus/mp/stream_buffer.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio stream_buffer 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #ifndef MP_STREAM_BUFFER_H__ 19 | #define MP_STREAM_BUFFER_H__ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #ifndef MP_STREAM_BUFFER_INITIAL_BUFFER_SIZE 27 | #define MP_STREAM_BUFFER_INITIAL_BUFFER_SIZE 8*1024 28 | #endif 29 | 30 | namespace mp { 31 | 32 | 33 | /** 34 | * stream_buffer: 35 | * +-------------------------------------------+ 36 | * | referenced | unparsed data | unused space | 37 | * +-------------------------------------------+ 38 | * ^ ^ data() ^ buffer() 39 | * | 40 | * | +---------------+ 41 | * | data_size() 42 | * | +--------------+ 43 | * | buffer_capacity() 44 | * | 45 | * | +-> data_consumed() 46 | * | 47 | * | +-> buffer_filled() 48 | * | 49 | * | reserve_buffer() +-> 50 | * | 51 | * +-- stream_buffer::ref (reference counter) 52 | * 53 | */ 54 | 55 | class stream_buffer { 56 | public: 57 | stream_buffer(size_t initial_buffer_size = MP_STREAM_BUFFER_INITIAL_BUFFER_SIZE); 58 | ~stream_buffer(); 59 | 60 | public: 61 | void reserve_buffer(size_t len, 62 | size_t initial_buffer_size = MP_STREAM_BUFFER_INITIAL_BUFFER_SIZE); 63 | 64 | void* buffer(); 65 | size_t buffer_capacity() const; 66 | void buffer_filled(size_t len); 67 | 68 | void* data(); 69 | size_t data_size() const; 70 | void data_consumed(size_t len); 71 | 72 | class ref { 73 | public: 74 | ref(); 75 | ref(const ref& o); 76 | ~ref(); 77 | void clear(); 78 | void swap(ref& x); 79 | private: 80 | std::vector m_array; 81 | struct each_incr; 82 | struct each_decr; 83 | private: 84 | void push(void* d); 85 | void move(void* d); 86 | friend class stream_buffer; 87 | }; 88 | 89 | ref retain(); 90 | void retain_to(ref* to); 91 | 92 | private: 93 | char* m_buffer; 94 | size_t m_used; 95 | size_t m_free; 96 | size_t m_off; 97 | ref m_ref; 98 | 99 | private: 100 | void expand_buffer(size_t len, size_t initial_buffer_size); 101 | 102 | typedef volatile unsigned int count_t; 103 | static void init_count(void* d); 104 | static void decr_count(void* d); 105 | static void incr_count(void* d); 106 | static count_t get_count(void* d); 107 | 108 | private: 109 | stream_buffer(const stream_buffer&); 110 | }; 111 | 112 | 113 | 114 | inline void stream_buffer::init_count(void* d) 115 | { 116 | *(volatile count_t*)d = 1; 117 | } 118 | 119 | inline void stream_buffer::decr_count(void* d) 120 | { 121 | //if(--*(count_t*)d == 0) { 122 | if(__sync_sub_and_fetch((count_t*)d, 1) == 0) { 123 | free(d); 124 | } 125 | } 126 | 127 | inline void stream_buffer::incr_count(void* d) 128 | { 129 | //++*(count_t*)d; 130 | __sync_add_and_fetch((count_t*)d, 1); 131 | } 132 | 133 | inline stream_buffer::count_t stream_buffer::get_count(void* d) 134 | { 135 | return *(count_t*)d; 136 | } 137 | 138 | 139 | struct stream_buffer::ref::each_incr { 140 | void operator() (void* d) 141 | { 142 | stream_buffer::incr_count(d); 143 | } 144 | }; 145 | 146 | struct stream_buffer::ref::each_decr { 147 | void operator() (void* d) 148 | { 149 | stream_buffer::decr_count(d); 150 | } 151 | }; 152 | 153 | inline stream_buffer::ref::ref() { } 154 | 155 | inline stream_buffer::ref::ref(const ref& o) : 156 | m_array(m_array) 157 | { 158 | std::for_each(m_array.begin(), m_array.end(), each_incr()); 159 | } 160 | 161 | inline void stream_buffer::ref::clear() 162 | { 163 | std::for_each(m_array.begin(), m_array.end(), each_decr()); 164 | m_array.clear(); 165 | } 166 | 167 | inline stream_buffer::ref::~ref() 168 | { 169 | clear(); 170 | } 171 | 172 | inline void stream_buffer::ref::push(void* d) 173 | { 174 | m_array.push_back(d); 175 | incr_count(d); 176 | } 177 | 178 | inline void stream_buffer::ref::move(void* d) 179 | { 180 | m_array.push_back(d); 181 | } 182 | 183 | inline void stream_buffer::ref::swap(ref& x) 184 | { 185 | m_array.swap(x.m_array); 186 | } 187 | 188 | 189 | inline stream_buffer::stream_buffer(size_t initial_buffer_size) : 190 | m_buffer(NULL), 191 | m_used(0), 192 | m_free(0), 193 | m_off(0) 194 | { 195 | const size_t initsz = std::max(initial_buffer_size, sizeof(count_t)); 196 | 197 | m_buffer = (char*)::malloc(initsz); 198 | if(!m_buffer) { throw std::bad_alloc(); } 199 | init_count(m_buffer); 200 | 201 | m_used = sizeof(count_t); 202 | m_free = initsz - m_used; 203 | m_off = sizeof(count_t); 204 | } 205 | 206 | inline stream_buffer::~stream_buffer() 207 | { 208 | decr_count(m_buffer); 209 | } 210 | 211 | inline void* stream_buffer::buffer() 212 | { 213 | return m_buffer + m_used; 214 | } 215 | 216 | inline size_t stream_buffer::buffer_capacity() const 217 | { 218 | return m_free; 219 | } 220 | 221 | inline void stream_buffer::buffer_filled(size_t len) 222 | { 223 | m_used += len; 224 | m_free -= len; 225 | } 226 | 227 | inline void* stream_buffer::data() 228 | { 229 | return m_buffer + m_off; 230 | } 231 | 232 | inline size_t stream_buffer::data_size() const 233 | { 234 | return m_used - m_off; 235 | } 236 | 237 | inline void stream_buffer::data_consumed(size_t len) 238 | { 239 | m_off += len; 240 | } 241 | 242 | 243 | inline stream_buffer::ref stream_buffer::retain() 244 | { 245 | ref r; 246 | r.swap(m_ref); 247 | return r; 248 | } 249 | 250 | inline void stream_buffer::retain_to(ref* to) 251 | { 252 | m_ref.push(m_buffer); 253 | to->swap(m_ref); 254 | m_ref.clear(); 255 | } 256 | 257 | inline void stream_buffer::reserve_buffer(size_t len, size_t initial_buffer_size) 258 | { 259 | if(m_used == m_off && get_count(m_buffer) == 1) { 260 | // rewind buffer 261 | m_free += m_used - sizeof(count_t); 262 | m_used = sizeof(count_t); 263 | m_off = sizeof(count_t); 264 | } 265 | if(m_free < len) { 266 | expand_buffer(len, initial_buffer_size); 267 | } 268 | } 269 | 270 | inline void stream_buffer::expand_buffer(size_t len, size_t initial_buffer_size) 271 | { 272 | if(m_off == sizeof(count_t) && get_count(m_buffer) == 1) { 273 | size_t next_size = (m_used + m_free) * 2; 274 | while(next_size < len + m_used) { next_size *= 2; } 275 | 276 | char* tmp = (char*)::realloc(m_buffer, next_size); 277 | if(!tmp) { throw std::bad_alloc(); } 278 | 279 | m_buffer = tmp; 280 | m_free = next_size - m_used; 281 | 282 | } else { 283 | const size_t initsz = std::max(initial_buffer_size, sizeof(count_t)); 284 | 285 | size_t next_size = initsz; // include sizeof(count_t) 286 | size_t not_used = m_used - m_off; 287 | while(next_size < len + not_used + sizeof(count_t)) { next_size *= 2; } 288 | 289 | char* tmp = (char*)::malloc(next_size); 290 | if(!tmp) { throw std::bad_alloc(); } 291 | init_count(tmp); 292 | 293 | try { 294 | m_ref.move(m_buffer); 295 | } catch (...) { free(tmp); throw; } 296 | 297 | memcpy(tmp+sizeof(count_t), m_buffer+m_off, not_used); 298 | 299 | m_buffer = tmp; 300 | m_used = not_used + sizeof(count_t); 301 | m_free = next_size - m_used; 302 | m_off = sizeof(count_t); 303 | } 304 | } 305 | 306 | 307 | } // namespace mp 308 | 309 | #endif /* mp/stream_buffer.h */ 310 | 311 | -------------------------------------------------------------------------------- /jubatus/mp/sync.hmpl: -------------------------------------------------------------------------------- 1 | // 2 | // mpio sync 3 | // 4 | // Copyright (C) 2009-2010 FURUHASHI Sadayuki 5 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | #ifndef MP_SYNC_H__ 20 | #define MP_SYNC_H__ 21 | 22 | #include "jubatus/mp/pthread.h" 23 | 24 | namespace mp { 25 | 26 | 27 | template 28 | class sync { 29 | public: 30 | sync() : m_obj() { } 31 | %varlen_each do |gen| 32 | template <[%gen.template%]> 33 | sync([%gen.args%]) : m_obj([%gen.params%]) { } 34 | %end 35 | 36 | ~sync() { } 37 | 38 | T& unsafe_ref() { return m_obj; } 39 | const T& unsafe_ref() const { return m_obj; } 40 | 41 | class ref { 42 | public: 43 | ref(sync& obj) : m_ref(NULL) 44 | { 45 | obj.m_mutex.lock(); 46 | m_ref = &obj; 47 | } 48 | 49 | ref() : m_ref(NULL) { } 50 | 51 | ~ref() { reset(); } 52 | 53 | void reset() 54 | { 55 | if(m_ref) { 56 | m_ref->m_mutex.unlock(); 57 | m_ref = NULL; 58 | } 59 | } 60 | 61 | void reset(sync& obj) 62 | { 63 | reset(); 64 | obj.m_mutex.lock(); 65 | m_ref = &obj; 66 | } 67 | 68 | void swap(sync& obj) 69 | { 70 | sync* tmp = m_ref; 71 | m_ref = obj.m_ref; 72 | obj.m_ref = tmp; 73 | } 74 | 75 | T& operator*() { return m_ref->m_obj; } 76 | T* operator->() { return &operator*(); } 77 | const T& operator*() const { return m_ref->m_obj; } 78 | const T* operator->() const { return &operator*(); } 79 | 80 | operator bool() const { return m_ref != NULL; } 81 | 82 | pthread_mutex& get_mutex() 83 | { 84 | return m_ref->m_mutex; 85 | } 86 | 87 | protected: 88 | sync* m_ref; 89 | 90 | private: 91 | ref(const ref&); 92 | }; 93 | 94 | class auto_ref : public ref { 95 | public: 96 | auto_ref(sync& obj) : ref(obj) { } 97 | auto_ref() { } 98 | ~auto_ref() { } 99 | 100 | auto_ref(auto_ref& o) 101 | { 102 | ref::m_ref = o.m_ref; 103 | o.m_ref = NULL; 104 | } 105 | 106 | auto_ref& operator= (auto_ref& o) 107 | { 108 | auto_ref(o).swap(*this); 109 | return *this; 110 | } 111 | }; 112 | 113 | auto_ref lock() 114 | { 115 | return auto_ref(*this); 116 | } 117 | 118 | private: 119 | T m_obj; 120 | pthread_mutex m_mutex; 121 | friend class ref; 122 | 123 | private: 124 | sync(const sync&); 125 | }; 126 | 127 | 128 | } // namespace mp 129 | 130 | #endif /* mp/sync.h */ 131 | 132 | %# vim: filetype=mplex 133 | -------------------------------------------------------------------------------- /jubatus/mp/tls_set.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio tls_set 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | #ifndef MP_TLS_SET_H__ 20 | #define MP_TLS_SET_H__ 21 | #ifdef MP_EXPERIMENTAL 22 | 23 | #include "jubatus/mp/pthread.h" 24 | #include "jubatus/mp/sync.h" 25 | #include 26 | #include 27 | 28 | namespace mp { 29 | 30 | 31 | class pthread_scoped_lock_multi { 32 | public: 33 | pthread_scoped_lock_multi() : m_vec(NULL) { } 34 | 35 | pthread_scoped_lock_multi(size_t size) : 36 | m_vec(new pthread_scoped_lock[size]) { } 37 | 38 | ~pthread_scoped_lock_multi() { delete[] m_vec; } 39 | 40 | void reset(size_t size) 41 | { 42 | if(m_vec) { delete[] m_vec; } 43 | m_vec = NULL; 44 | m_vec = new pthread_scoped_lock[size]; 45 | } 46 | 47 | pthread_scoped_lock& operator[] (size_t index) 48 | { 49 | return m_vec[index]; 50 | } 51 | 52 | const pthread_scoped_lock& operator[] (size_t index) const 53 | { 54 | return m_vec[index]; 55 | } 56 | 57 | private: 58 | pthread_scoped_lock* m_vec; 59 | 60 | private: 61 | pthread_scoped_lock_multi(const pthread_scoped_lock_multi&); 62 | }; 63 | 64 | 65 | template 66 | class tls_set { 67 | public: 68 | tls_set() 69 | { 70 | int err = pthread_key_create(&m_key, &mp::object_destructor); 71 | if(err) { throw pthread_error(err, "failed to create TLS key"); } 72 | } 73 | 74 | ~tls_set() 75 | { } 76 | 77 | void init_thread(const T& data = T()) 78 | { 79 | all_vec_ref ref(m_all_vec); 80 | 81 | std::auto_ptr e(new element(data)); 82 | 83 | ref->push_back(e.get()); 84 | 85 | int err = pthread_setspecific(m_key, (void*)e.get()); 86 | if(err) { 87 | ref->pop_back(); 88 | throw pthread_error(err, "failed to init TLS"); 89 | } 90 | 91 | e.release(); 92 | } 93 | 94 | void update_self(const T& data) 95 | { 96 | element* e = (element*)pthread_getspecific(m_key); 97 | pthread_scoped_lock lk(e->mutex); 98 | e->data = data; 99 | } 100 | 101 | T& get_self(pthread_scoped_lock* lk) 102 | { 103 | element* e = (element*)pthread_getspecific(m_key); 104 | lk->relock(e->mutex); 105 | return e->data; 106 | } 107 | 108 | T& get_self(const pthread_scoped_lock_multi& mlk) 109 | { 110 | element* e = (element*)pthread_getspecific(m_key); 111 | return e->data; 112 | } 113 | 114 | void update_all(const T& data) 115 | { 116 | all_vec_ref ref(m_all_vec); 117 | for(typename all_vec_t::iterator it(ref->begin()), 118 | it_end(ref->end()); it != it_end; ++it) { 119 | pthread_scoped_lock lk(it->mutex); 120 | it->data = data; 121 | } 122 | } 123 | 124 | template 125 | void get_all(F func) 126 | { 127 | all_vec_ref ref(m_all_vec); 128 | for(typename all_vec_t::iterator it(ref->begin()), 129 | it_end(ref->end()); it != it_end; ++it) { 130 | pthread_scoped_lock lk(it->mutex); 131 | func(it->data); 132 | } 133 | } 134 | 135 | void update_all(const T& data, const pthread_scoped_lock_multi& mlk) 136 | { 137 | all_vec_ref ref(m_all_vec); 138 | for(typename all_vec_t::iterator it(ref->begin()), 139 | it_end(ref->end()); it != it_end; ++it) { 140 | it->data = data; 141 | } 142 | } 143 | 144 | template 145 | void get_all(F func, const pthread_scoped_lock_multi& mlk) 146 | { 147 | all_vec_ref ref(m_all_vec); 148 | for(typename all_vec_t::iterator it(ref->begin()), 149 | it_end(ref->end()); it != it_end; ++it) { 150 | func(it->data); 151 | } 152 | } 153 | 154 | void lock_all(pthread_scoped_lock_multi* mlk) 155 | { 156 | all_vec_ref ref(m_all_vec); 157 | mlk->reset(ref->size()); 158 | for(size_t i=0; i < ref->size(); ++i) { 159 | (*mlk)[i].relock((*ref)[i]->mutex); 160 | } 161 | } 162 | 163 | private: 164 | struct element { 165 | element(const T& data) : data(data) { } 166 | ~element() { } 167 | T data; 168 | pthread_mutex mutex; 169 | }; 170 | 171 | pthread_key_t m_key; 172 | 173 | typedef std::vector all_vec_t; 174 | typedef typename mp::sync::ref all_vec_ref; 175 | mp::sync m_all_vec; 176 | }; 177 | 178 | 179 | } // namespace mp 180 | 181 | #endif /* MP_EXPERIMENTAL */ 182 | #endif /* mp/tls_set.h */ 183 | 184 | -------------------------------------------------------------------------------- /jubatus/mp/unordered.h: -------------------------------------------------------------------------------- 1 | // 2 | // mp::unordered 3 | // 4 | // Copyright (C) 2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | 19 | #ifndef MP_UNORDERED_H__ 20 | #define MP_UNORDERED_H__ 21 | 22 | #if defined(MP_UNORDERED_MAP_BOOST) 23 | #include 24 | #include 25 | #include 26 | namespace mp { 27 | using std::tr1::unordered_map; 28 | using std::tr1::unordered_set; 29 | using std::tr1::unordered_multimap; 30 | using std::tr1::unordered_multiset; 31 | //using std::tr1::hash_range; 32 | //using std::tr1::hash_combine; 33 | template struct hash : public std::tr1::hash { }; 34 | } 35 | 36 | #elif defined(MP_UNORDERED_MAP_BOOST_ORG) 37 | #include 38 | #include 39 | namespace mp { 40 | using boost::unordered_map; 41 | using boost::unordered_set; 42 | using boost::unordered_multimap; 43 | using boost::unordered_multiset; 44 | template struct hash : public boost::hash { }; 45 | } 46 | 47 | #elif defined(MP_UNORDERED_MAP_STANDARD) 48 | #include 49 | #include 50 | namespace mp { 51 | using std::unordered_map; 52 | using std::unordered_set; 53 | using std::unordered_multimap; 54 | using std::unordered_multiset; 55 | template struct hash : public std::hash { }; 56 | } 57 | 58 | #else 59 | #include 60 | #include 61 | #include 62 | namespace mp { 63 | using std::tr1::unordered_map; 64 | using std::tr1::unordered_set; 65 | using std::tr1::unordered_multimap; 66 | using std::tr1::unordered_multiset; 67 | template struct hash : public std::tr1::hash { }; 68 | } 69 | #endif 70 | 71 | #endif /* mp/unordered.h */ 72 | 73 | -------------------------------------------------------------------------------- /jubatus/mp/unordered_map.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 2 | 3 | #include "jubatus/mp/unordered.h" 4 | -------------------------------------------------------------------------------- /jubatus/mp/unordered_set.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 2 | 3 | #include "jubatus/mp/unordered.h" 4 | -------------------------------------------------------------------------------- /jubatus/mp/utilize.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio utilize 3 | // 4 | // Copyright (C) 2009-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #ifndef MP_UTILIZE_H__ 19 | #define MP_UTILIZE_H__ 20 | 21 | 22 | #define MP_UTILIZE \ 23 | struct mp_util; \ 24 | friend struct mp_util 25 | 26 | #define MP_UTIL_DEF(name) \ 27 | struct name::mp_util : public name 28 | 29 | #define MP_UTIL_IMPL(name) \ 30 | name::mp_util 31 | 32 | #define MP_UTIL \ 33 | (*static_cast(this)) 34 | 35 | #define MP_UTIL_FROM(self) \ 36 | (*static_cast(self)) 37 | 38 | 39 | #endif /* mp/utilze.h */ 40 | 41 | -------------------------------------------------------------------------------- /jubatus/mp/wavy.hmpl: -------------------------------------------------------------------------------- 1 | // 2 | // mpio wavy 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | #ifndef MP_WAVY_H__ 20 | #define MP_WAVY_H__ 21 | 22 | #include "jubatus/mp/functional.h" 23 | #include "jubatus/mp/memory.h" 24 | #include "jubatus/mp/pthread.h" 25 | #include "jubatus/mp/object_delete.h" 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | namespace mp { 39 | namespace wavy { 40 | 41 | 42 | class basic_handler; 43 | class handler; 44 | class event; 45 | class xfer; 46 | 47 | typedef shared_ptr shared_handler; 48 | typedef weak_ptr weak_handler; 49 | 50 | 51 | class loop { 52 | public: 53 | typedef mp::wavy::basic_handler basic_handler; 54 | typedef mp::wavy::handler handler; 55 | typedef mp::wavy::event event; 56 | 57 | loop(); 58 | loop(function thread_init_func); 59 | 60 | ~loop(); 61 | 62 | void start(size_t num); 63 | 64 | void run(size_t num); // run = start + join 65 | 66 | bool is_running() const; 67 | 68 | void run_once(); 69 | void run_nonblock(); 70 | 71 | void end(); 72 | bool is_end() const; 73 | 74 | void join(); 75 | void detach(); 76 | 77 | void add_thread(size_t num); 78 | 79 | 80 | void remove_handler(int fd); 81 | 82 | 83 | typedef function connect_callback_t; 84 | 85 | void connect( 86 | int socket_family, int socket_type, int protocol, 87 | const sockaddr* addr, socklen_t addrlen, 88 | const timespec* timeout, connect_callback_t callback); 89 | 90 | void connect( 91 | int socket_family, int socket_type, int protocol, 92 | const sockaddr* addr, socklen_t addrlen, 93 | double timeout_sec, connect_callback_t callback); 94 | 95 | 96 | typedef function listen_callback_t; 97 | 98 | int listen( 99 | int socket_family, int socket_type, int protocol, 100 | const sockaddr* addr, socklen_t addrlen, 101 | listen_callback_t callback, 102 | int backlog = 1024); 103 | 104 | 105 | int add_timer(const timespec* value, const timespec* interval, 106 | function callback); 107 | 108 | int add_timer(double value_sec, double interval_sec, 109 | function callback); 110 | 111 | void remove_timer(int ident); 112 | 113 | 114 | int add_signal(int signo, function callback); 115 | 116 | void remove_signal(int ident); 117 | 118 | 119 | 120 | typedef void (*finalize_t)(void* user); 121 | 122 | 123 | void write(int fd, const void* buf, size_t size); 124 | 125 | void write(int fd, const void* buf, size_t size, 126 | finalize_t fin, void* user); 127 | 128 | template 129 | void write(int fd, const void* buf, size_t size, 130 | std::auto_ptr& fin); 131 | 132 | template 133 | void write(int fd, const void* buf, size_t size, 134 | mp::shared_ptr fin); 135 | 136 | 137 | void writev(int fd, const struct iovec* vec, size_t veclen, 138 | finalize_t fin, void* user); 139 | 140 | template 141 | void writev(int fd, const struct iovec* vec, size_t veclen, 142 | std::auto_ptr& fin); 143 | 144 | template 145 | void writev(int fd, const struct iovec* vec, size_t veclen, 146 | mp::shared_ptr fin); 147 | 148 | 149 | void sendfile(int fd, int infd, uint64_t off, size_t size, 150 | finalize_t fin, void* user); 151 | 152 | void hsendfile(int fd, 153 | const void* header, size_t header_size, 154 | int infd, uint64_t off, size_t size, 155 | finalize_t fin, void* user); 156 | 157 | void hvsendfile(int fd, 158 | const struct iovec* header_vec, size_t header_veclen, 159 | int infd, uint64_t off, size_t size, 160 | finalize_t fin, void* user); 161 | 162 | 163 | void commit(int fd, xfer* xf); 164 | 165 | 166 | void flush(); 167 | 168 | 169 | template 170 | shared_ptr add_handler(); 171 | %varlen_each do |gen| 172 | template 173 | shared_ptr add_handler([%gen.args%]); 174 | %end 175 | 176 | 177 | template 178 | void submit(F f); 179 | %varlen_each do |gen| 180 | template 181 | void submit(F f, [%gen.args%]); 182 | %end 183 | 184 | 185 | private: 186 | shared_handler add_handler_impl(shared_handler sh); 187 | 188 | typedef function task_t; 189 | void submit_impl(task_t f); 190 | 191 | private: 192 | void* m_impl; 193 | 194 | loop(const loop&); 195 | }; 196 | 197 | 198 | class event { 199 | protected: 200 | event() { } 201 | ~event() { } 202 | public: 203 | void more(); 204 | void next(); 205 | void remove(); 206 | private: 207 | event(const event&); 208 | }; 209 | 210 | 211 | class xfer { 212 | public: 213 | xfer(); 214 | ~xfer(); 215 | 216 | typedef loop::finalize_t finalize_t; 217 | 218 | void push_write(const void* buf, size_t size); 219 | 220 | void push_writev(const struct iovec* vec, size_t veclen); 221 | 222 | void push_sendfile(int infd, uint64_t off, size_t len); 223 | 224 | void push_finalize(finalize_t fin, void* user); 225 | 226 | template 227 | void push_finalize(std::auto_ptr fin); 228 | 229 | template 230 | void push_finalize(mp::shared_ptr fin); 231 | 232 | bool empty() const; 233 | 234 | void clear(); 235 | 236 | void migrate(xfer* to); 237 | 238 | protected: 239 | char* m_head; 240 | char* m_tail; 241 | size_t m_free; 242 | 243 | void reserve(size_t reqsz); 244 | 245 | private: 246 | xfer(const xfer&); 247 | }; 248 | 249 | 250 | struct basic_handler { 251 | public: 252 | typedef bool (*callback_t)(basic_handler*, event&); 253 | 254 | template 255 | basic_handler(int ident, IMPL* self) : 256 | m_ident(ident), m_callback(&static_callback) { } 257 | 258 | basic_handler(int ident, callback_t callback) : 259 | m_ident(ident), m_callback(callback) { } 260 | 261 | virtual ~basic_handler() { } 262 | 263 | int ident() const { return m_ident; } 264 | 265 | int fd() const { return ident(); } 266 | 267 | bool operator() (event& e); 268 | 269 | private: 270 | int m_ident; 271 | 272 | callback_t m_callback; 273 | 274 | private: 275 | template 276 | static bool static_callback(basic_handler* self, event& e) 277 | { 278 | return (*static_cast(self))(e); 279 | } 280 | 281 | basic_handler(); 282 | basic_handler(const basic_handler&); 283 | }; 284 | 285 | 286 | struct handler : public mp::enable_shared_from_this, public basic_handler { 287 | public: 288 | handler(int fd) : basic_handler(fd, &callback_on_read) { } 289 | 290 | ~handler() { ::close(fd()); } 291 | 292 | virtual void on_read(event& e) = 0; 293 | 294 | public: 295 | template 296 | shared_ptr shared_self() 297 | { 298 | return static_pointer_cast(enable_shared_from_this::shared_from_this()); 299 | } 300 | 301 | template 302 | shared_ptr shared_self() const 303 | { 304 | return static_pointer_cast(enable_shared_from_this::shared_from_this()); 305 | } 306 | 307 | private: 308 | static inline bool callback_on_read(basic_handler* self, event& e) 309 | { 310 | static_cast(self)->on_read(e); 311 | return true; 312 | } 313 | friend class basic_handler; 314 | }; 315 | 316 | 317 | inline bool basic_handler::operator() (event& e) 318 | { 319 | if(m_callback == handler::callback_on_read) { 320 | return handler::callback_on_read(this, e); 321 | } else { 322 | return m_callback(this, e); 323 | } 324 | } 325 | 326 | 327 | template 328 | shared_ptr loop::add_handler() 329 | { return static_pointer_cast(add_handler_impl( 330 | shared_ptr(new Handler())) ); } 331 | %varlen_each do |gen| 332 | template 333 | shared_ptr loop::add_handler([%gen.args%]) 334 | { return static_pointer_cast(add_handler_impl( 335 | shared_ptr(new Handler([%gen.params%]))) ); } 336 | %end 337 | 338 | template 339 | inline void loop::submit(F f) 340 | { submit_impl(task_t(f)); } 341 | %varlen_each do |gen| 342 | template 343 | inline void loop::submit(F f, [%gen.args%]) 344 | { submit_impl(bind(f, [%gen.params%])); } 345 | %end 346 | 347 | 348 | inline xfer::xfer() : 349 | m_head(NULL), m_tail(NULL), m_free(0) { } 350 | 351 | inline xfer::~xfer() 352 | { 353 | if(m_head) { 354 | clear(); 355 | ::free(m_head); 356 | } 357 | } 358 | 359 | inline bool xfer::empty() const 360 | { 361 | return m_head == m_tail; 362 | } 363 | 364 | template 365 | inline void xfer::push_finalize(std::auto_ptr fin) 366 | { 367 | push_finalize(&mp::object_delete, reinterpret_cast(fin.get())); 368 | fin.release(); 369 | } 370 | 371 | template 372 | inline void xfer::push_finalize(mp::shared_ptr fin) 373 | { 374 | std::auto_ptr > afin(new mp::shared_ptr(fin)); 375 | push_finalize(afin); 376 | } 377 | 378 | template 379 | inline void loop::write(int fd, const void* buf, size_t size, 380 | std::auto_ptr& fin) 381 | { 382 | write(fd, buf, size, &mp::object_delete, fin.get()); 383 | fin.release(); 384 | } 385 | 386 | template 387 | inline void loop::write(int fd, const void* buf, size_t size, 388 | mp::shared_ptr fin) 389 | { 390 | std::auto_ptr > afin(new mp::shared_ptr(fin)); 391 | write(fd, buf, size, afin); 392 | } 393 | 394 | template 395 | inline void loop::writev(int fd, const struct iovec* vec, size_t veclen, 396 | std::auto_ptr& fin) 397 | { 398 | writev(fd, vec, veclen, &mp::object_delete, fin.get()); 399 | fin.release(); 400 | } 401 | 402 | template 403 | inline void loop::writev(int fd, const struct iovec* vec, size_t veclen, 404 | mp::shared_ptr fin) 405 | { 406 | std::auto_ptr > afin(new mp::shared_ptr(fin)); 407 | writev(fd, vec, veclen, afin); 408 | } 409 | 410 | 411 | } // namespace wavy 412 | } // namespace mp 413 | 414 | #endif /* mp/wavy.h */ 415 | 416 | %# vim: filetype=mplex 417 | -------------------------------------------------------------------------------- /mpl.rb: -------------------------------------------------------------------------------- 1 | 2 | ARGS_MAX = 16 3 | 4 | class VarlenGenerator 5 | def initialize 6 | @n = 1 7 | end 8 | 9 | def template 10 | each_join {|i| "typename A#{i}" } 11 | end 12 | 13 | def args 14 | each_join {|i| "A#{i} a#{i}" } 15 | end 16 | 17 | def args_ptr 18 | each_join {|i| "A#{i}* a#{i}" } 19 | end 20 | 21 | def args_ref 22 | each_join {|i| "A#{i}& a#{i}" } 23 | end 24 | 25 | def args_const_ref 26 | each_join {|i| "const A#{i}& a#{i}" } 27 | end 28 | 29 | def types 30 | each_join {|i| "A#{i}" } 31 | end 32 | 33 | def types_ptr 34 | each_join {|i| "A#{i}*" } 35 | end 36 | 37 | def types_ref 38 | each_join {|i| "A#{i}&" } 39 | end 40 | 41 | def types_const_ref 42 | each_join {|i| "const A#{i}&" } 43 | end 44 | 45 | def params 46 | each_join {|i| "a#{i}" } 47 | end 48 | 49 | def params_ptr 50 | each_join {|i| "&#{i}*" } 51 | end 52 | 53 | def each_join(&block) 54 | Array.new(@n) {|i| block.call(i+1) }.join(', ') 55 | end 56 | 57 | def each(&block) 58 | 1.upto(@n).each(&block) 59 | nil 60 | end 61 | 62 | def run(&block) 63 | ARGS_MAX.times { 64 | block.call(self) 65 | @n += 1 66 | } 67 | end 68 | end 69 | 70 | def varlen_each(&block) 71 | VarlenGenerator.new.run(&block) 72 | end 73 | 74 | -------------------------------------------------------------------------------- /mplex: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # Mplex: Extended Metaprogramming Library 4 | # 5 | # Copyright (c) 2009-2010 FURUHASHI Sadayuki 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | # THE SOFTWARE. 24 | # 25 | 26 | class Mplex 27 | def initialize(src, fname = "(mplex)") 28 | @script = self.class.compile(src) 29 | b = nil; Object.new.instance_eval { b = binding } 30 | @proc = eval("Proc.new{#{@script}}", b, fname) 31 | end 32 | attr_reader :script 33 | 34 | def result(context = nil, output = "") 35 | self.class.with_context(context, output) {|ctx| 36 | ctx.instance_eval(&@proc) 37 | } 38 | end 39 | 40 | def self.result(src, context = nil, fname = "(mplex)", output = "") 41 | with_context(context, output) {|ctx| 42 | ctx.instance_eval(compile(src), fname) 43 | } 44 | end 45 | 46 | def self.file(fname, context = nil) 47 | self.result(File.read(fname), context, fname) 48 | end 49 | 50 | def self.write(fname, outfname, context = nil) 51 | out = self.result(File.read(fname), context, fname) 52 | File.open(outfname, "w") {|f| f.write(out) } 53 | out 54 | end 55 | 56 | def self.script(src) 57 | compile(src) 58 | end 59 | 60 | private 61 | def self.with_context(context, output, &block) 62 | context ||= Object.new 63 | save = context.instance_variable_get(:@_mplexout) 64 | context.instance_variable_set(:@_mplexout, output) 65 | block.call(context) 66 | context.instance_variable_set(:@_mplexout, save) 67 | output 68 | end 69 | 70 | def self.compile(src) 71 | # MPLEX_COMPILE_BEGIN 72 | o = "" 73 | k = false 74 | src.each_line {|t| 75 | (k = false; o << "\n"; next) if k && t == "__END__\n" 76 | (o << t; next) if k 77 | (k = true; o << "\n"; next) if t == "__BEGIN__\n" 78 | 79 | c, l = t.split(/^[ \t]*%/,2) 80 | (o << l; next) if l 81 | 82 | c, a, b = t.split(/[ \t]*\%\|([a-z0-9\,\*\&\(\)]*)\|/,2) 83 | t = "[%:#{b.strip} do |#{a}|%]#{c+"\n"}[%:end%]" if b 84 | 85 | c, q = t.split(/[ \t]*\%\>/,2) 86 | t = "[%:(%]#{c+"\n"}[%:)#{q.strip}%]" if q 87 | 88 | s = t.split(/(?:\[\%(\:?.*?)\%\]|\{\{(\:?.*?\}*)\}\})/m) 89 | s.each_with_index {|m,i| 90 | (o << "#{m[1..-1]};"; next) if m[0] == ?: && i % 2 == 1 91 | (o << "@_mplexout.concat((#{m}).to_s);"; next) if i % 2 == 1 92 | o << "@_mplexout.concat(#{m.dump});" unless m.empty? 93 | } 94 | o << "\n" 95 | } 96 | o << "@_mplexout" 97 | # MPLEX_COMPILE_END 98 | end 99 | end 100 | 101 | #!/usr/bin/env ruby 102 | # 103 | # Mplex: Extended Metaprogramming Library 104 | # 105 | # Copyright (c) 2009-2010 FURUHASHI Sadayuki 106 | # 107 | # Permission is hereby granted, free of charge, to any person obtaining a copy 108 | # of this software and associated documentation files (the "Software"), to deal 109 | # in the Software without restriction, including without limitation the rights 110 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 111 | # copies of the Software, and to permit persons to whom the Software is 112 | # furnished to do so, subject to the following conditions: 113 | # 114 | # The above copyright notice and this permission notice shall be included in 115 | # all copies or substantial portions of the Software. 116 | # 117 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 118 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 119 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 120 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 121 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 122 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 123 | # THE SOFTWARE. 124 | # 125 | 126 | require 'optparse' 127 | 128 | op = OptionParser.new 129 | op.banner += " input..." 130 | 131 | finputs = "-" 132 | foutput = "-" 133 | fctx = nil 134 | libs = [] 135 | script = false 136 | 137 | op.on("-c file", "context ruby script") {|v| fctx = v } 138 | op.on("-o file", "output file") {|v| foutput = v } 139 | op.on("-r library", "load library") {|v| libs << v } 140 | op.on("-x", "print ruby script") {|v| script = true } 141 | 142 | (class<= 2 158 | raise "multiple stdin" 159 | end 160 | 161 | rescue 162 | usage 163 | end 164 | 165 | def fread(path) 166 | path == "-" ? $stdin.read : File.read(path) 167 | end 168 | 169 | def fname(path) 170 | path == "-" ? "(stdin)" : path 171 | end 172 | 173 | libs.each {|lib| require lib } 174 | 175 | inputs = finputs.map {|f| [fread(f), fname(f)] } 176 | 177 | result = "" 178 | if script 179 | inputs.each {|src, name| 180 | result.concat Mplex.script(src) 181 | } 182 | 183 | else 184 | if fctx 185 | b = nil; Object.instance_eval { b = binding } 186 | ctx = eval("lambda{#{fread(fctx)}}.call", b, fname(fctx)) 187 | end 188 | ctx ||= Object.new 189 | 190 | inputs.each {|src, name| 191 | Mplex.result(src, ctx, name, result) 192 | } 193 | end 194 | 195 | if foutput == "-" 196 | $stdout.write(result) 197 | else 198 | File.open(foutput, "w") {|f| 199 | f.write result 200 | } 201 | end 202 | 203 | -------------------------------------------------------------------------------- /mpsrc/Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 2 | 3 | lib_LTLIBRARIES = libjubatus_mpio.la 4 | 5 | libjubatus_mpio_la_LDFLAGS = -version-info 4:3:4 6 | libjubatus_mpio_la_CPPFLAGS = -I.. 7 | 8 | libjubatus_mpio_la_SOURCES = \ 9 | wavy_connect.cc \ 10 | wavy_listen.cc \ 11 | wavy_loop.cc \ 12 | wavy_signal.cc \ 13 | wavy_timer.cc 14 | 15 | noinst_HEADERS = \ 16 | pp.h \ 17 | wavy_kernel.h \ 18 | wavy_kernel_epoll.h \ 19 | wavy_kernel_kqueue.h \ 20 | wavy_loop.h \ 21 | wavy_out.h \ 22 | wavy_out.cc \ 23 | wavy_signal.h \ 24 | wavy_timer.h 25 | 26 | -------------------------------------------------------------------------------- /mpsrc/pp.h: -------------------------------------------------------------------------------- 1 | #ifndef MP_PP_H__ 2 | #define MP_PP_H__ 3 | 4 | #define MP_PP_STR(s) #s 5 | #define MP_PP_XSTR(s) MP_PP_STR(s) 6 | #define MP_PP_CONCAT(a,b) a##b 7 | #define MP_PP_XCONCAT(a,b) MP_PP_CONCAT(a,b) 8 | #define MP_PP_HEADER(dir, prefix, file, suffix) \ 9 | MP_PP_XSTR( MP_PP_XCONCAT(dir/prefix ## file, suffix).h ) 10 | 11 | #endif /* mp/pp.h */ 12 | 13 | -------------------------------------------------------------------------------- /mpsrc/wavy_connect.cc: -------------------------------------------------------------------------------- 1 | // 2 | // mpio wavy connect 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #include "wavy_loop.h" 19 | #include "wavy_timer.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | namespace mp { 28 | namespace wavy { 29 | 30 | namespace { 31 | 32 | 33 | class connect_task { 34 | public: 35 | typedef loop::connect_callback_t connect_callback_t; 36 | 37 | struct pack { 38 | int socket_family; 39 | int socket_type; 40 | int protocol; 41 | socklen_t addrlen; 42 | int timeout_msec; 43 | sockaddr addr[0]; 44 | }; 45 | 46 | connect_task( 47 | int socket_family, int socket_type, int protocol, 48 | const sockaddr* addr, socklen_t addrlen, 49 | const timespec* timeout, connect_callback_t& callback) : 50 | m((pack*)::malloc(sizeof(pack)+addrlen)), 51 | m_callback(callback) 52 | { 53 | if(!m) { throw std::bad_alloc(); } 54 | m->socket_family = socket_family; 55 | m->socket_type = socket_type; 56 | m->protocol = protocol; 57 | m->addrlen = addrlen; 58 | if(timeout && (timeout->tv_sec && timeout->tv_nsec)) { 59 | m->timeout_msec = timeout->tv_sec + timeout->tv_nsec * 1e6; 60 | } else { 61 | m->timeout_msec = -1; 62 | } 63 | ::memcpy(m->addr, addr, addrlen); 64 | } 65 | 66 | void operator() () 67 | { 68 | int err = 0; 69 | int fd = ::socket(m->socket_family, m->socket_type, m->protocol); 70 | if(fd < 0) { 71 | err = errno; 72 | goto out; 73 | } 74 | 75 | if(::fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { 76 | goto error; 77 | } 78 | 79 | if(::connect(fd, m->addr, m->addrlen) >= 0) { 80 | // connect success 81 | goto out; 82 | } 83 | 84 | if(errno != EINPROGRESS) { 85 | goto error; 86 | } 87 | 88 | while(true) { 89 | struct pollfd pf = {fd, POLLOUT, 0}; 90 | int ret = ::poll(&pf, 1, m->timeout_msec); 91 | if(ret < 0) { 92 | if(errno == EINTR) { continue; } 93 | goto error; 94 | } 95 | 96 | if(ret == 0) { 97 | errno = ETIMEDOUT; 98 | goto error; 99 | } 100 | 101 | { 102 | int value = 0; 103 | int len = sizeof(value); 104 | if(::getsockopt(fd, SOL_SOCKET, SO_ERROR, 105 | &value, (socklen_t*)&len) < 0) { 106 | goto error; 107 | } 108 | if(value != 0) { 109 | errno = value; 110 | goto error; 111 | } 112 | goto out; 113 | } 114 | } 115 | 116 | error: 117 | err = errno; 118 | 119 | ::close(fd); 120 | fd = -1; 121 | 122 | out: 123 | ::free(m); 124 | m_callback(fd, err); 125 | } 126 | 127 | private: 128 | pack* m; 129 | connect_callback_t m_callback; 130 | 131 | private: 132 | connect_task(); 133 | }; 134 | 135 | 136 | } // noname namespace 137 | 138 | 139 | void loop::connect( 140 | int socket_family, int socket_type, int protocol, 141 | const sockaddr* addr, socklen_t addrlen, 142 | const timespec* timeout, connect_callback_t callback) 143 | { 144 | connect_task t( 145 | socket_family, socket_type, protocol, 146 | addr, addrlen, timeout, callback); 147 | submit(t); 148 | } 149 | 150 | 151 | #if 0 152 | namespace { 153 | 154 | 155 | class connect_handler : public basic_handler { 156 | public: 157 | typedef loop::connect_callback_t connect_callback_t; 158 | 159 | connect_handler(int ident, connect_callback_t callback) : 160 | basic_handler(ident, this), 161 | m_done(false), m_callback(callback) 162 | { } 163 | 164 | ~connect_handler() 165 | { } 166 | 167 | bool operator() (event& e) 168 | { 169 | int fd = ident(); 170 | 171 | if(!__sync_bool_compare_and_swap(&m_done, false, true)) { 172 | ::close(fd); 173 | return false; 174 | } 175 | 176 | int err = 0; 177 | 178 | int value = 0; 179 | int len = sizeof(value); 180 | 181 | if(::getsockopt(fd, SOL_SOCKET, SO_ERROR, 182 | &value, (socklen_t*)&len) < 0) { 183 | goto errno_error; 184 | } 185 | 186 | if(value != 0) { 187 | err = value; 188 | goto specific_error; 189 | } 190 | 191 | goto out; 192 | 193 | errno_error: 194 | err = errno; 195 | 196 | specific_error: 197 | ::close(fd); 198 | fd = -1; 199 | 200 | out: 201 | e.remove(); 202 | m_callback(fd, err); 203 | return false; 204 | } 205 | 206 | class timeout_handler : kernel_timer, public basic_handler { 207 | public: 208 | timeout_handler(kernel& kern, const timespec* timeout, 209 | shared_handler handler) : 210 | kernel_timer(kern, timeout, NULL), 211 | basic_handler(timer_ident(), this), 212 | m_handler( static_pointer_cast(handler) ) 213 | { } 214 | 215 | ~timeout_handler() { } 216 | 217 | bool operator() (event& e) 218 | { 219 | shared_ptr h(m_handler.lock()); 220 | if(h) { 221 | h->fail(ETIMEDOUT); 222 | } 223 | return false; 224 | } 225 | 226 | private: 227 | weak_ptr m_handler; 228 | }; 229 | 230 | void set_timer(loop* lo, shared_ptr& timer) 231 | { 232 | m_loop = lo; 233 | m_timer = weak_ptr(timer); 234 | } 235 | 236 | void fail(int err) 237 | { 238 | if(!__sync_bool_compare_and_swap(&m_done, false, true)) { 239 | return; 240 | } 241 | m_callback(-1, err); 242 | } 243 | 244 | private: 245 | bool m_done; 246 | connect_callback_t m_callback; 247 | 248 | loop* m_loop; 249 | weak_ptr m_timer; 250 | }; 251 | 252 | 253 | } // noname namespace 254 | 255 | 256 | void loop::connect( 257 | int socket_family, int socket_type, int protocol, 258 | const sockaddr* addr, socklen_t addrlen, 259 | const timespec* timeout, connect_callback_t callback) 260 | { 261 | shared_ptr sh; 262 | 263 | int err = 0; 264 | int fd = ::socket(socket_family, socket_type, protocol); 265 | if(fd < 0) { 266 | err = errno; 267 | goto out; 268 | } 269 | 270 | if(::fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { 271 | goto errno_error; 272 | } 273 | 274 | if(::connect(fd, addr, addrlen) >= 0) { 275 | // connect success 276 | goto out; 277 | } 278 | 279 | if(errno != EINPROGRESS) { 280 | goto errno_error; 281 | } 282 | 283 | try { 284 | // FIXME EVKERNEL_WRITE 285 | sh = add_handler(fd, callback); 286 | } catch (...) { 287 | err = 0; 288 | goto specific_error; 289 | } 290 | 291 | if(timeout == NULL || (timeout->tv_sec == 0 && 292 | timeout->tv_nsec == 0)) { 293 | return; 294 | } 295 | 296 | try { 297 | shared_ptr timer( 298 | new connect_handler::timeout_handler( 299 | ANON_impl->get_kernel(), timeout, sh)); 300 | 301 | ANON_impl->set_handler(timer); 302 | 303 | sh->set_timer(this, timer); 304 | 305 | return; 306 | 307 | } catch (const system_error& e) { 308 | sh->fail(0); 309 | return; 310 | 311 | } catch (...) { 312 | sh->fail(0); 313 | return; 314 | } 315 | 316 | errno_error: 317 | err = errno; 318 | 319 | specific_error: 320 | ::close(fd); 321 | fd = -1; 322 | 323 | out: 324 | submit(callback, fd, err); 325 | } 326 | #endif 327 | 328 | 329 | void loop::connect( 330 | int socket_family, int socket_type, int protocol, 331 | const sockaddr* addr, socklen_t addrlen, 332 | double timeout_sec, connect_callback_t callback) 333 | { 334 | struct timespec timeout = { 335 | static_cast(timeout_sec), 336 | static_cast(((timeout_sec - (double)(long)timeout_sec) * 1e9)) }; 337 | return connect(socket_family, socket_type, protocol, 338 | addr, addrlen, &timeout, callback); 339 | } 340 | 341 | 342 | } // namespace wavy 343 | } // namespace mp 344 | 345 | -------------------------------------------------------------------------------- /mpsrc/wavy_kernel.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio wavy kernel 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #ifndef MP_WAVY_KERNEL_H__ 19 | #define MP_WAVY_KERNEL_H__ 20 | 21 | #include "pp.h" 22 | 23 | #ifndef MP_WAVY_KERNEL 24 | # if defined(HAVE_SYS_EPOLL_H) 25 | # define MP_WAVY_KERNEL epoll 26 | # elif defined(HAVE_SYS_EVENT_H) 27 | # define MP_WAVY_KERNEL kqueue 28 | # else 29 | # if defined(__linux__) 30 | # define MP_WAVY_KERNEL epoll 31 | # elif defined(__APPLE__) && defined(__MACH__) 32 | # define MP_WAVY_KERNEL kqueue 33 | # elif defined(__FreeBSD__) || defined(__NetBSD__) 34 | # define MP_WAVY_KERNEL kqueue 35 | # elif defined(__sun__) 36 | # error Solaris Event Port is not supported. FIXME. mpsrc/wavy_kernel_eventport.cc 37 | # else 38 | # error This OS is not supported. FIXME. mpsrc/wavy_kernel_select.cc 39 | # endif 40 | # endif 41 | #endif 42 | 43 | #define MP_WAVY_KERNEL_HEADER(sys) \ 44 | MP_PP_HEADER(.,wavy_kernel_,sys,) 45 | 46 | #ifndef MP_WAVY_KERNEL_BACKLOG_SIZE 47 | #define MP_WAVY_KERNEL_BACKLOG_SIZE 1024 48 | #endif 49 | 50 | #include MP_WAVY_KERNEL_HEADER(MP_WAVY_KERNEL) 51 | 52 | //static const short EVKERNEL_READ; 53 | //static const short EVKERNEL_WRITE; 54 | // 55 | //class kernel { 56 | //public: 57 | // kernel(); 58 | // ~kernel(); 59 | // 60 | // size_t max() const; 61 | // 62 | // 63 | // struct event { 64 | // int ident() const; 65 | // }; 66 | // 67 | // 68 | // int add_fd(int fd, short event); 69 | // int remove_fd(int fd, short event); 70 | // 71 | // 72 | // class timer { 73 | // public: 74 | // timer(); 75 | // ~timer(); 76 | // int ident() const; 77 | // private: 78 | // signal(const signal&); 79 | // }; 80 | // 81 | // int add_timer(timer* tm, const timespec* value, const timespec* interval); 82 | // int remove_timer(int ident); 83 | // static int read_timer(event e); 84 | // 85 | // 86 | // class signal { 87 | // public: 88 | // signal(); 89 | // ~signal(); 90 | // int ident() const { return xident; } 91 | // private: 92 | // signal(const signal&); 93 | // }; 94 | // 95 | // int add_signal(signal* sg, int signo); 96 | // int remove_signal(int ident); 97 | // static int read_signal(event e); 98 | // 99 | // 100 | // int add_kernel(kernel* pt); 101 | // int ident() const; 102 | // 103 | // 104 | // class backlog { 105 | // public: 106 | // backlog(); 107 | // ~backlog(); 108 | // event operator[] (int n) const; 109 | // private: 110 | // backlog(const backlog&); 111 | // }; 112 | // 113 | // int wait(backlog* result); 114 | // int wait(backlog* result, int timeout_msec); 115 | // 116 | // int reactivate(event e); 117 | // int remove(event e); 118 | // 119 | //private: 120 | // kernel(const kernel&); 121 | //}; 122 | 123 | #endif /* wavy_kernel.h */ 124 | 125 | -------------------------------------------------------------------------------- /mpsrc/wavy_kernel_epoll.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio wavy kernel epoll 3 | // 4 | // Copyright (C) 2008-20010 FURUHASHI Sadayuki 5 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | #ifndef MP_WAVY_KERNEL_EPOLL_H__ 20 | #define MP_WAVY_KERNEL_EPOLL_H__ 21 | 22 | #include "jubatus/mp/exception.h" 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #ifndef DISABLE_TIMERFD 34 | #include 35 | #endif 36 | 37 | #ifndef DISABLE_SIGNALFD 38 | // work around for glibc header signalfd.h error:expected initializer before ‘throw 39 | #if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 8) 40 | #undef __THROW 41 | #define __THROW 42 | #endif 43 | #include 44 | #endif 45 | 46 | namespace mp { 47 | namespace wavy { 48 | 49 | 50 | static const short EVKERNEL_READ = EPOLLIN; 51 | static const short EVKERNEL_WRITE = EPOLLOUT; 52 | 53 | 54 | class kernel { 55 | public: 56 | kernel() : m_ep(epoll_create(MP_WAVY_KERNEL_BACKLOG_SIZE)) 57 | { 58 | if(m_ep < 0) { 59 | throw system_error(errno, "failed to initialize epoll"); 60 | } 61 | } 62 | 63 | ~kernel() 64 | { 65 | ::close(m_ep); 66 | } 67 | 68 | size_t max() const 69 | { 70 | struct rlimit rbuf; 71 | if(::getrlimit(RLIMIT_NOFILE, &rbuf) < 0) { 72 | throw system_error(errno, "getrlimit() failed"); 73 | } 74 | return rbuf.rlim_cur; 75 | } 76 | 77 | 78 | class event { 79 | public: 80 | event() { } 81 | explicit event(uint64_t data) : m_data(data) { } 82 | ~event() { } 83 | 84 | int ident() const { return m_data & 0xffffffff; } 85 | 86 | private: 87 | uint64_t m_data; 88 | 89 | uint64_t data() const { return m_data; } 90 | uint32_t events() const { return m_data >> 32; } 91 | friend class kernel; 92 | }; 93 | 94 | 95 | int add_fd(int fd, short event) 96 | { 97 | struct epoll_event ev; 98 | ::memset(&ev, 0, sizeof(ev)); // FIXME valgrind 99 | ev.events = event | EPOLLONESHOT; 100 | ev.data.u64 = ((uint64_t)fd) | ((uint64_t)ev.events << 32); 101 | return epoll_ctl(m_ep, EPOLL_CTL_ADD, fd, &ev); 102 | } 103 | 104 | int remove_fd(int fd, short event) 105 | { 106 | return epoll_ctl(m_ep, EPOLL_CTL_DEL, fd, NULL); 107 | } 108 | 109 | 110 | #ifndef DISABLE_TIMERFD 111 | class timer { 112 | public: 113 | timer() : fd(-1) { } 114 | ~timer() { 115 | if(fd >= 0) { ::close(fd); } 116 | } 117 | 118 | int ident() const { return fd; } 119 | 120 | private: 121 | int fd; 122 | friend class kernel; 123 | timer(const timer&); 124 | }; 125 | 126 | int add_timer(timer* tm, const timespec* value, const timespec* interval) 127 | { 128 | int fd = timerfd_create(CLOCK_REALTIME, 0); 129 | if(fd < 0) { 130 | return -1; 131 | } 132 | 133 | if(::fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { 134 | ::close(fd); 135 | return -1; 136 | } 137 | 138 | struct itimerspec itimer; 139 | ::memset(&itimer, 0, sizeof(itimer)); 140 | if(interval) { 141 | itimer.it_interval = *interval; 142 | } 143 | if(value) { 144 | itimer.it_value = *value; 145 | } else { 146 | itimer.it_value = itimer.it_interval; 147 | } 148 | 149 | if(timerfd_settime(fd, 0, &itimer, NULL) < 0) { 150 | ::close(fd); 151 | return -1; 152 | } 153 | 154 | if(add_fd(fd, EVKERNEL_READ) < 0) { 155 | ::close(fd); 156 | return -1; 157 | } 158 | 159 | tm->fd = fd; 160 | return fd; 161 | } 162 | 163 | int remove_timer(int ident) 164 | { 165 | return remove_fd(ident, EVKERNEL_READ); 166 | } 167 | 168 | static int read_timer(event e) 169 | { 170 | uint64_t exp; 171 | if(read(e.ident(), &exp, sizeof(uint64_t)) <= 0) { 172 | return -1; 173 | } 174 | return 0; 175 | } 176 | #else // DISABLE_TIMERFD 177 | class timer { 178 | public: 179 | timer() : fd(-1), fd_writer(-1) { } 180 | ~timer() { 181 | if(fd >= 0) { 182 | timer_delete(timer_id); 183 | ::close(fd); 184 | } 185 | if(fd_writer >= 0) { 186 | ::close(fd_writer); 187 | } 188 | } 189 | 190 | int ident() const { return fd; } 191 | 192 | private: 193 | int fd; 194 | int fd_writer; 195 | timer_t timer_id; 196 | friend class kernel; 197 | timer(const timer&); 198 | }; 199 | 200 | static void timer_thread_handler(sigval_t val) 201 | { 202 | int pipefd = val.sival_int; 203 | const char *p = (const char*)&val; 204 | const char * const endp = p + sizeof(sigval_t); 205 | while(p < endp) { 206 | ssize_t wl = ::write(pipefd, p, endp - p); 207 | if(wl < 0) { 208 | if(errno == EINTR || errno == EAGAIN) continue; 209 | ::close(pipefd); 210 | return; 211 | } 212 | p += wl; 213 | } 214 | } 215 | 216 | int add_timer(timer* tm, const timespec* value, const timespec* interval) 217 | { 218 | int pipefd[2]; 219 | if(pipe(pipefd) < 0) { 220 | return -1; 221 | } 222 | 223 | if(::fcntl(pipefd[0], F_SETFL, O_NONBLOCK) < 0) { 224 | ::close(pipefd[1]); 225 | ::close(pipefd[0]); 226 | return -1; 227 | } 228 | 229 | struct itimerspec itimer; 230 | ::memset(&itimer, 0, sizeof(itimer)); 231 | if(interval) { 232 | itimer.it_interval = *interval; 233 | } 234 | if(value) { 235 | itimer.it_value = *value; 236 | } else { 237 | itimer.it_value = itimer.it_interval; 238 | } 239 | 240 | timer_t timer_id; 241 | struct sigevent ev; 242 | ev.sigev_notify = SIGEV_THREAD; 243 | ev.sigev_value.sival_int = pipefd[1]; 244 | ev.sigev_notify_function = kernel::timer_thread_handler; 245 | ev.sigev_notify_attributes = 0; 246 | 247 | if(timer_create(CLOCK_MONOTONIC, &ev, &timer_id) < 0) { 248 | ::close(pipefd[1]); 249 | ::close(pipefd[0]); 250 | return -1; 251 | } 252 | 253 | if(timer_settime(timer_id, 0, &itimer, 0) < 0) { 254 | ::close(pipefd[1]); 255 | ::close(pipefd[0]); 256 | return -1; 257 | } 258 | 259 | if(add_fd(pipefd[0], EVKERNEL_READ) < 0) { 260 | ::close(pipefd[1]); 261 | ::close(pipefd[0]); 262 | return -1; 263 | } 264 | 265 | tm->fd = pipefd[0]; 266 | tm->fd_writer = pipefd[1]; 267 | tm->timer_id = timer_id; 268 | 269 | return pipefd[0]; 270 | } 271 | 272 | int remove_timer(int ident) 273 | { 274 | return remove_fd(ident, EVKERNEL_READ); 275 | } 276 | 277 | static int read_timer(event e) 278 | { 279 | sigval_t val; 280 | if(read(e.ident(), &val, sizeof(sigval_t)) <= 0) { 281 | return -1; 282 | } 283 | return 0; 284 | } 285 | #endif 286 | 287 | 288 | #ifndef DISABLE_SIGNALFD 289 | class signal { 290 | public: 291 | signal() : fd(-1) { } 292 | ~signal() { 293 | if(fd >= 0) { ::close(fd); } 294 | } 295 | 296 | int ident() const { return fd; } 297 | 298 | private: 299 | int fd; 300 | friend class kernel; 301 | signal(const signal&); 302 | }; 303 | 304 | int add_signal(signal* sg, int signo) 305 | { 306 | sigset_t mask; 307 | sigemptyset(&mask); 308 | sigaddset(&mask, signo); 309 | 310 | int fd = signalfd(-1, &mask, 0); 311 | if(fd < 0) { 312 | return -1; 313 | } 314 | 315 | if(::fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { 316 | ::close(fd); 317 | return -1; 318 | } 319 | 320 | if(add_fd(fd, EVKERNEL_READ) < 0) { 321 | ::close(fd); 322 | return -1; 323 | } 324 | 325 | sg->fd = fd; 326 | return fd; 327 | } 328 | 329 | int remove_signal(int ident) 330 | { 331 | return remove_fd(ident, EVKERNEL_READ); 332 | } 333 | 334 | static int read_signal(event e) 335 | { 336 | signalfd_siginfo info; 337 | if(read(e.ident(), &info, sizeof(info)) <= 0) { 338 | return -1; 339 | } 340 | return 0; 341 | } 342 | #endif 343 | 344 | 345 | int add_kernel(kernel* kern) 346 | { 347 | if(add_fd(kern->m_ep, EVKERNEL_READ) < 0) { 348 | return -1; 349 | } 350 | return kern->m_ep; 351 | } 352 | 353 | int ident() const 354 | { 355 | return m_ep; 356 | } 357 | 358 | 359 | class backlog { 360 | public: 361 | backlog() 362 | { 363 | buf = (struct epoll_event*)::calloc( 364 | sizeof(struct epoll_event), 365 | MP_WAVY_KERNEL_BACKLOG_SIZE); 366 | if(!buf) { throw std::bad_alloc(); } 367 | } 368 | 369 | ~backlog() 370 | { 371 | ::free(buf); 372 | } 373 | 374 | event operator[] (int n) 375 | { 376 | return event(buf[n].data.u64); 377 | } 378 | 379 | private: 380 | struct epoll_event* buf; 381 | friend class kernel; 382 | backlog(const backlog&); 383 | }; 384 | 385 | int wait(backlog* result) 386 | { 387 | return wait(result, -1); 388 | } 389 | 390 | int wait(backlog* result, int timeout_msec) 391 | { 392 | return epoll_wait(m_ep, result->buf, 393 | MP_WAVY_KERNEL_BACKLOG_SIZE, timeout_msec); 394 | } 395 | 396 | int reactivate(event e) 397 | { 398 | struct epoll_event ev; 399 | ::memset(&ev, 0, sizeof(ev)); // FIXME valgrind 400 | ev.events = e.events(); 401 | ev.data.u64 = e.data(); 402 | return epoll_ctl(m_ep, EPOLL_CTL_MOD, e.ident(), &ev); 403 | } 404 | 405 | int remove(event e) 406 | { 407 | return epoll_ctl(m_ep, EPOLL_CTL_DEL, e.ident(), NULL); 408 | } 409 | 410 | private: 411 | int m_ep; 412 | 413 | private: 414 | kernel(const kernel&); 415 | }; 416 | 417 | 418 | } // namespace wavy 419 | } // namespace mp 420 | 421 | #endif /* wavy_kernel_epoll.h */ 422 | 423 | -------------------------------------------------------------------------------- /mpsrc/wavy_kernel_kqueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio wavy kernel kqueue 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | #ifndef MP_WAVY_KERNEL_KQUEUE_H__ 20 | #define MP_WAVY_KERNEL_KQUEUE_H__ 21 | 22 | #include "jubatus/mp/exception.h" 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #ifndef MP_WAVY_KERNEL_KQUEUE_XIDENT_MAX 34 | #define MP_WAVY_KERNEL_KQUEUE_XIDENT_MAX 256 35 | #endif 36 | 37 | namespace mp { 38 | namespace wavy { 39 | 40 | 41 | static const short EVKERNEL_READ = EVFILT_READ; 42 | static const short EVKERNEL_WRITE = EVFILT_WRITE; 43 | 44 | 45 | class kernel { 46 | public: 47 | kernel() : m_kq(kqueue()) 48 | { 49 | struct rlimit rbuf; 50 | if(::getrlimit(RLIMIT_NOFILE, &rbuf) < 0) { 51 | ::close(m_kq); 52 | throw system_error(errno, "getrlimit() failed"); 53 | } 54 | m_fdmax = rbuf.rlim_cur; 55 | 56 | if(m_kq < 0) { 57 | throw system_error(errno, "failed to initialize kqueue"); 58 | } 59 | 60 | memset(m_xident, 0, sizeof(m_xident)); 61 | m_xident_index = 0; 62 | } 63 | 64 | ~kernel() 65 | { 66 | ::close(m_kq); 67 | } 68 | 69 | size_t max() const 70 | { 71 | return m_fdmax + MP_WAVY_KERNEL_KQUEUE_XIDENT_MAX; 72 | } 73 | 74 | 75 | private: 76 | int alloc_xident() 77 | { 78 | for(unsigned int i=0; i < MP_WAVY_KERNEL_KQUEUE_XIDENT_MAX*2; ++i) { 79 | unsigned int x = __sync_fetch_and_add(&m_xident_index, 1) % MP_WAVY_KERNEL_KQUEUE_XIDENT_MAX; 80 | if(__sync_bool_compare_and_swap(&m_xident[x], false, true)) { 81 | return m_fdmax + x; 82 | } 83 | } 84 | errno = EMFILE; 85 | return -1; 86 | } 87 | 88 | bool free_xident(int xident) 89 | { 90 | bool* xv = m_xident + (xident - m_fdmax); 91 | // FIXME cas? 92 | if(*xv) { 93 | *xv = false; 94 | return true; 95 | } 96 | return false; 97 | } 98 | 99 | int set_event(uintptr_t ident, short filter, u_short flags, 100 | u_int fflags, intptr_t data, void* udata) 101 | { 102 | struct kevent kev; 103 | EV_SET(&kev, ident, filter, flags, fflags, data, udata); 104 | return kevent(m_kq, &kev, 1, NULL, 0, NULL); 105 | } 106 | 107 | 108 | public: 109 | class event { 110 | public: 111 | event() { } 112 | explicit event(struct kevent kev_) : kev(kev_) { } 113 | ~event() { } 114 | 115 | int ident() const { 116 | if(kev.filter == EVFILT_SIGNAL) { 117 | return (int)(intptr_t)kev.udata; 118 | } 119 | return kev.ident; 120 | } 121 | 122 | private: 123 | struct kevent kev; 124 | friend class kernel; 125 | }; 126 | 127 | 128 | int add_fd(int fd, short event) 129 | { 130 | return set_event(fd, event, EV_ADD|EV_ONESHOT, 0, 0, NULL); 131 | } 132 | 133 | int remove_fd(int fd, short event) 134 | { 135 | return set_event(fd, event, EV_DELETE, 0, 0, NULL); 136 | } 137 | 138 | 139 | class timer { 140 | public: 141 | timer() : xident(-1) { } 142 | ~timer() { 143 | if(xident >= 0) { 144 | kern->remove_timer(xident); 145 | kern->free_xident(xident); 146 | } 147 | } 148 | 149 | int ident() const { return xident; } 150 | 151 | private: 152 | int xident; 153 | kernel* kern; 154 | friend class kernel; 155 | timer(const timer&); 156 | }; 157 | 158 | friend class timer; 159 | 160 | int add_timer(timer* tm, const timespec* value, const timespec* interval) 161 | { 162 | int xident = alloc_xident(); 163 | if(xident < 0) { 164 | return -1; 165 | } 166 | 167 | unsigned long data; 168 | unsigned long udata; 169 | if(interval) { 170 | udata = interval->tv_sec*1000 + interval->tv_nsec/1000/1000; 171 | } else { 172 | udata = 0; 173 | } 174 | if(value) { 175 | data = value->tv_sec*1000 + value->tv_nsec/1000/1000; 176 | } else { 177 | data = udata; 178 | } 179 | 180 | if(set_event(xident, EVFILT_TIMER, EV_ADD|EV_ONESHOT, 0, 181 | data, (void*)udata) < 0) { 182 | free_xident(xident); 183 | return -1; 184 | } 185 | 186 | tm->xident = xident; 187 | tm->kern = this; 188 | return xident; 189 | } 190 | 191 | int remove_timer(int ident) 192 | { 193 | return set_event(ident, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 194 | } 195 | 196 | static int read_timer(event e) 197 | { 198 | return 0; 199 | } 200 | 201 | 202 | class signal { 203 | public: 204 | signal() : xident(-1) { } 205 | ~signal() { 206 | if(xident >= 0) { 207 | kern->remove_signal(xident); 208 | kern->free_xident(xident); 209 | } 210 | } 211 | 212 | int ident() const { return xident; } 213 | 214 | private: 215 | int xident; 216 | kernel* kern; 217 | friend class kernel; 218 | signal(const signal&); 219 | }; 220 | 221 | friend class signal; 222 | 223 | int add_signal(signal* sg, int signo) 224 | { 225 | int xident = alloc_xident(); 226 | if(xident < 0) { 227 | return -1; 228 | } 229 | 230 | if(set_event(signo,EVFILT_SIGNAL, EV_ADD|EV_ONESHOT, 0, 231 | 0, (void*)xident) < 0) { 232 | free_xident(xident); 233 | return -1; 234 | } 235 | 236 | sg->xident = xident; 237 | sg->kern = this; 238 | return xident; 239 | } 240 | 241 | int remove_signal(int ident) 242 | { 243 | return set_event(ident, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL); 244 | } 245 | 246 | static int read_signal(event e) 247 | { 248 | return 0; 249 | } 250 | 251 | 252 | int add_kernel(kernel* kern) 253 | { 254 | if(add_fd(kern->m_kq, EVKERNEL_READ) < 0) { 255 | return -1; 256 | } 257 | return kern->m_kq; 258 | } 259 | 260 | int ident() const 261 | { 262 | return m_kq; 263 | } 264 | 265 | 266 | class backlog { 267 | public: 268 | backlog() 269 | { 270 | buf = (struct kevent*)::calloc( 271 | sizeof(struct kevent), 272 | MP_WAVY_KERNEL_BACKLOG_SIZE); 273 | if(!buf) { throw std::bad_alloc(); } 274 | } 275 | 276 | ~backlog() 277 | { 278 | ::free(buf); 279 | } 280 | 281 | event operator[] (int n) const 282 | { 283 | return event(buf[n]); 284 | } 285 | 286 | private: 287 | struct kevent* buf; 288 | friend class kernel; 289 | backlog(const backlog&); 290 | }; 291 | 292 | int wait(backlog* result) 293 | { 294 | return kevent(m_kq, NULL, 0, result->buf, 295 | MP_WAVY_KERNEL_BACKLOG_SIZE, NULL); 296 | } 297 | 298 | int wait(backlog* result, int timeout_msec) 299 | { 300 | struct timespec ts; 301 | ts.tv_sec = timeout_msec / 1000; 302 | ts.tv_nsec = (timeout_msec % 1000) * 1000000; 303 | return kevent(m_kq, NULL, 0, result->buf, 304 | MP_WAVY_KERNEL_BACKLOG_SIZE, &ts); 305 | } 306 | 307 | int reactivate(event e) 308 | { 309 | switch(e.kev.filter) { 310 | case EVFILT_READ: 311 | return add_fd(e.ident(), EVFILT_READ); 312 | 313 | case EVFILT_WRITE: 314 | return add_fd(e.ident(), EVFILT_WRITE); 315 | 316 | case EVFILT_TIMER: { 317 | unsigned long data = (uintptr_t)e.kev.udata; 318 | return set_event(e.ident(), EVFILT_TIMER, 319 | EV_ADD|EV_ONESHOT, 0, data, (void*)data); 320 | } 321 | 322 | case EVFILT_SIGNAL: { 323 | int signo = (long)e.kev.ident; 324 | void* xident = e.kev.udata; 325 | return set_event(signo, EVFILT_SIGNAL, 326 | EV_ADD|EV_ONESHOT, 0, 0, xident); 327 | } 328 | 329 | default: 330 | return -1; 331 | } 332 | } 333 | 334 | int remove(event e) 335 | { 336 | switch(e.kev.filter) { 337 | case EVFILT_READ: 338 | case EVFILT_WRITE: 339 | return 0; 340 | 341 | case EVFILT_TIMER: 342 | case EVFILT_SIGNAL: 343 | return 0; 344 | 345 | default: 346 | return -1; 347 | } 348 | } 349 | 350 | private: 351 | int m_kq; 352 | size_t m_fdmax; 353 | 354 | bool m_xident[MP_WAVY_KERNEL_KQUEUE_XIDENT_MAX]; 355 | unsigned int m_xident_index; 356 | 357 | kernel(const kernel&); 358 | }; 359 | 360 | 361 | } // namespace wavy 362 | } // namespace mp 363 | 364 | #endif /* wavy_kernel_kqueue.h */ 365 | 366 | -------------------------------------------------------------------------------- /mpsrc/wavy_listen.cc: -------------------------------------------------------------------------------- 1 | // 2 | // mpio wavy listen 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #include "wavy_loop.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | namespace mp { 26 | namespace wavy { 27 | 28 | namespace { 29 | 30 | 31 | class listen_handler : public handler { 32 | public: 33 | typedef loop::listen_callback_t listen_callback_t; 34 | 35 | listen_handler(int fd, listen_callback_t callback) : 36 | handler(fd), m_callback(callback) { } 37 | 38 | ~listen_handler() { } 39 | 40 | void on_read(event& e) 41 | { 42 | while(true) { 43 | int err = 0; 44 | int sock = ::accept(fd(), NULL, NULL); 45 | if(sock < 0) { 46 | err = errno; 47 | if(err == EAGAIN || err == EWOULDBLOCK || err == EINTR) { 48 | return; 49 | } 50 | 51 | m_callback(sock, err); 52 | 53 | ::sleep(1); 54 | return; 55 | } 56 | 57 | try { 58 | m_callback(sock, err); 59 | } catch (...) { 60 | ::close(sock); 61 | } 62 | } 63 | } 64 | 65 | private: 66 | listen_callback_t m_callback; 67 | 68 | private: 69 | listen_handler(); 70 | listen_handler(const listen_handler&); 71 | }; 72 | 73 | 74 | } // noname namespace 75 | 76 | 77 | int loop::listen( 78 | int socket_family, int socket_type, int protocol, 79 | const sockaddr* addr, socklen_t addrlen, 80 | listen_callback_t callback, 81 | int backlog) 82 | { 83 | int lsock = ::socket(socket_family, socket_type, protocol); 84 | if(lsock < 0) { 85 | throw mp::system_error(errno, "socket() failed"); 86 | } 87 | 88 | int on = 1; 89 | if(::setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { 90 | ::close(lsock); 91 | throw system_error(errno, "setsockopt failed"); 92 | } 93 | 94 | if(::bind(lsock, addr, addrlen) < 0) { 95 | ::close(lsock); 96 | throw system_error(errno, "bind failed"); 97 | } 98 | 99 | if(::listen(lsock, backlog) < 0) { 100 | ::close(lsock); 101 | throw system_error(errno, "listen failed"); 102 | } 103 | 104 | try { 105 | add_handler(lsock, callback); 106 | } catch (...) { 107 | ::close(lsock); 108 | throw; 109 | } 110 | 111 | return lsock; 112 | } 113 | 114 | 115 | } // namespace wavy 116 | } // namespace mp 117 | 118 | -------------------------------------------------------------------------------- /mpsrc/wavy_loop.cc: -------------------------------------------------------------------------------- 1 | // 2 | // mpio wavy loop 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #include "wavy_loop.h" 19 | #include "wavy_out.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | // linkage hack for out::out, out::poll_event and out::write_event 27 | #include "wavy_out.cc" 28 | 29 | #ifndef MP_WAVY_TASK_QUEUE_LIMIT 30 | #define MP_WAVY_TASK_QUEUE_LIMIT 16 31 | #endif 32 | 33 | namespace mp { 34 | namespace wavy { 35 | namespace { 36 | 37 | 38 | loop_impl::loop_impl(function thread_init_func) : 39 | m_off(0), m_num(0), m_pollable(true), 40 | m_thread_init_func(thread_init_func), 41 | m_end_flag(false) 42 | { 43 | m_state = new shared_handler[m_kernel.max()]; 44 | 45 | // add out handler 46 | { 47 | m_out.reset(new out); 48 | set_handler(m_out); 49 | get_kernel().add_kernel(&m_out->get_kernel()); 50 | } 51 | } 52 | 53 | loop_impl::~loop_impl() 54 | { 55 | end(); 56 | join(); // FIXME detached? 57 | { 58 | pthread_scoped_lock lk(m_mutex); 59 | m_cond.broadcast(); 60 | } 61 | delete[] m_state; 62 | } 63 | 64 | void loop_impl::end() 65 | { 66 | m_end_flag = true; 67 | { 68 | pthread_scoped_lock lk(m_mutex); 69 | m_cond.broadcast(); 70 | // if(m_poll_thread) { // FIXME signal_stop 71 | // pthread_kill(m_poll_thread, SIGALRM); 72 | // } 73 | } 74 | } 75 | 76 | bool loop_impl::is_end() const 77 | { 78 | return m_end_flag; 79 | } 80 | 81 | 82 | void loop_impl::join() 83 | { 84 | for(workers_t::iterator it(m_workers.begin()); 85 | it != m_workers.end(); ++it) { 86 | try { 87 | it->join(); 88 | } catch (mp::pthread_error& e) { 89 | if(e.code == EDEADLK) { 90 | it->detach(); 91 | } else { 92 | throw e; 93 | } 94 | } 95 | } 96 | m_workers.clear(); 97 | } 98 | 99 | void loop_impl::detach() 100 | { 101 | for(workers_t::iterator it(m_workers.begin()); 102 | it != m_workers.end(); ++it) { 103 | it->detach(); 104 | } 105 | } 106 | 107 | 108 | void loop_impl::start(size_t num) 109 | { 110 | pthread_scoped_lock lk(m_mutex); 111 | if(is_running()) { 112 | // FIXME exception 113 | throw std::runtime_error("loop is already running"); 114 | } 115 | add_thread(num); 116 | } 117 | 118 | void loop_impl::add_thread(size_t num) 119 | { 120 | for(size_t i=0; i < num; ++i) { 121 | m_workers.push_back( pthread_thread() ); 122 | try { 123 | m_workers.back().run( 124 | bind(&loop_impl::thread_main, this)); 125 | } catch (...) { 126 | m_workers.pop_back(); 127 | throw; 128 | } 129 | } 130 | } 131 | 132 | bool loop_impl::is_running() const 133 | { 134 | return !m_workers.empty(); 135 | } 136 | 137 | void loop_impl::submit_impl(task_t& f) 138 | { 139 | pthread_scoped_lock lk(m_mutex); 140 | m_task_queue.push(f); 141 | m_cond.signal(); 142 | } 143 | 144 | 145 | shared_ptr loop_impl::add_handler_impl(shared_ptr sh) 146 | { 147 | int fd = sh->ident(); 148 | if(::fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { 149 | throw system_error(errno, "failed to set nonblock flag"); 150 | } 151 | 152 | set_handler(sh); 153 | get_kernel().add_fd(fd, EVKERNEL_READ); 154 | 155 | return sh; 156 | } 157 | 158 | void loop_impl::remove_handler(int fd) 159 | { 160 | m_out->clear_xfer(fd); 161 | reset_handler(fd); 162 | m_kernel.remove_fd(fd, EVKERNEL_READ); 163 | } 164 | 165 | 166 | void loop_impl::do_task(pthread_scoped_lock& lk) 167 | { 168 | task_t ev = m_task_queue.front(); 169 | m_task_queue.pop(); 170 | 171 | bool last = m_task_queue.empty(); 172 | if(!last) { m_cond.signal(); } 173 | 174 | lk.unlock(); 175 | 176 | try { 177 | ev(); 178 | } catch (...) { } 179 | 180 | if(last) { 181 | lk.relock(m_mutex); 182 | m_flush_cond.broadcast(); 183 | } 184 | } 185 | 186 | void loop_impl::do_out(pthread_scoped_lock& lk) 187 | { 188 | kernel::event ke = m_out->next(); 189 | 190 | lk.unlock(); 191 | 192 | if(m_out->write_event(ke)) { 193 | lk.relock(m_mutex); 194 | m_flush_cond.broadcast(); 195 | } 196 | } 197 | 198 | void loop_impl::thread_main() 199 | { 200 | retry: 201 | while(true) { 202 | pthread_scoped_lock lk(m_mutex); 203 | 204 | retry_task: 205 | if(m_end_flag) { break; } 206 | 207 | kernel::event ke; 208 | 209 | if(!m_more_queue.empty()) { 210 | ke = m_more_queue.front(); 211 | m_more_queue.pop(); 212 | goto process_handler; 213 | } 214 | 215 | if(m_out->has_queue()) { 216 | do_out(lk); 217 | goto retry; 218 | } 219 | if(!m_pollable) { 220 | if(!m_task_queue.empty()) { 221 | do_task(lk); 222 | goto retry; 223 | } else { 224 | m_cond.wait(m_mutex); 225 | goto retry_task; 226 | } 227 | } else if(m_task_queue.size() > MP_WAVY_TASK_QUEUE_LIMIT) { 228 | do_task(lk); 229 | goto retry; 230 | } 231 | 232 | if(m_num == m_off) { 233 | m_pollable = false; 234 | //m_poll_thread = pthread_self(); // FIXME signal_stop 235 | lk.unlock(); 236 | 237 | retry_poll: 238 | int num = m_kernel.wait(&m_backlog, 1000); 239 | 240 | if(num <= 0) { 241 | if(num == 0 || errno == EINTR || errno == EAGAIN) { 242 | if(m_end_flag) { 243 | m_pollable = true; 244 | break; 245 | } 246 | goto retry_poll; 247 | } else { 248 | throw system_error(errno, "wavy kernel event failed"); 249 | } 250 | } 251 | 252 | lk.relock(m_mutex); 253 | m_off = 0; 254 | m_num = num; 255 | 256 | //m_poll_thread = 0; // FIXME signal_stop 257 | m_pollable = true; 258 | m_cond.signal(); 259 | } 260 | 261 | ke = m_backlog[m_off++]; 262 | 263 | process_handler: 264 | int ident = ke.ident(); 265 | 266 | if(ident == m_out->ident()) { 267 | m_out->poll_event(); 268 | lk.unlock(); 269 | 270 | m_kernel.reactivate(ke); 271 | 272 | } else { 273 | lk.unlock(); 274 | 275 | event_impl e(this, ke); 276 | shared_handler h = m_state[ident]; 277 | 278 | bool cont = false; 279 | if(h) { 280 | try { 281 | cont = (*h)(e); 282 | } catch (...) { } 283 | } 284 | 285 | if(!e.is_reactivated()) { 286 | if(e.is_removed()) { 287 | goto retry; 288 | } 289 | if(!cont) { 290 | m_kernel.remove(ke); 291 | reset_handler(ident); 292 | goto retry; 293 | } 294 | m_kernel.reactivate(ke); 295 | } 296 | } 297 | 298 | } // while(true) 299 | } 300 | 301 | 302 | inline void loop_impl::run_once() 303 | { 304 | pthread_scoped_lock lk(m_mutex); 305 | run_once(lk, true); 306 | } 307 | 308 | inline void loop_impl::run_nonblock() 309 | { 310 | pthread_scoped_lock lk(m_mutex); 311 | run_once(lk, false); 312 | } 313 | 314 | void loop_impl::run_once(pthread_scoped_lock& lk, bool block) 315 | { 316 | if(m_end_flag) { return; } 317 | 318 | kernel::event ke; 319 | 320 | if(!m_more_queue.empty()) { 321 | ke = m_more_queue.front(); 322 | m_more_queue.pop(); 323 | goto process_handler; 324 | } 325 | 326 | if(!m_pollable) { 327 | do_queue: 328 | if(m_out->has_queue()) { 329 | do_out(lk); 330 | } else if(!m_task_queue.empty()) { 331 | do_task(lk); 332 | } else if(block) { 333 | m_cond.wait(m_mutex); 334 | } 335 | return; 336 | } else if(!m_task_queue.empty()) { 337 | do_task(lk); 338 | return; 339 | } else if(m_out->has_queue()) { 340 | do_out(lk); // FIXME 341 | return; 342 | } 343 | 344 | if(m_num == m_off) { 345 | m_pollable = false; 346 | lk.unlock(); 347 | 348 | int num = m_kernel.wait(&m_backlog, block ? 1000 : 0); 349 | 350 | if(num <= 0) { 351 | if(num == 0 || errno == EINTR || errno == EAGAIN) { 352 | m_pollable = true; 353 | if(!block) { 354 | goto do_queue; 355 | } 356 | return; 357 | } else { 358 | throw system_error(errno, "wavy kernel event failed"); 359 | } 360 | } 361 | 362 | lk.relock(m_mutex); 363 | m_off = 0; 364 | m_num = num; 365 | 366 | m_pollable = true; 367 | m_cond.signal(); 368 | } 369 | 370 | ke = m_backlog[m_off++]; 371 | 372 | process_handler: 373 | int ident = ke.ident(); 374 | 375 | if(ident == m_out->ident()) { 376 | m_out->poll_event(); 377 | lk.unlock(); 378 | 379 | m_kernel.reactivate(ke); 380 | 381 | } else { 382 | lk.unlock(); 383 | 384 | event_impl e(this, ke); 385 | shared_handler h = m_state[ident]; 386 | 387 | bool cont = false; 388 | if(h) { 389 | try { 390 | cont = (*h)(e); 391 | } catch (...) { } 392 | } 393 | 394 | if(!e.is_reactivated()) { 395 | if(e.is_removed()) { 396 | return; 397 | } 398 | if(!cont) { 399 | m_kernel.remove(ke); 400 | reset_handler(ident); 401 | return; 402 | } 403 | m_kernel.reactivate(ke); 404 | } 405 | } 406 | } 407 | 408 | 409 | void loop_impl::flush() 410 | { 411 | pthread_scoped_lock lk(m_mutex); 412 | while(!m_out->empty() || !m_task_queue.empty()) { 413 | if(is_running()) { 414 | m_flush_cond.wait(m_mutex); 415 | } else { 416 | run_once(lk); 417 | if(!lk.owns()) { 418 | lk.relock(m_mutex); 419 | } 420 | } 421 | } 422 | } 423 | 424 | 425 | void loop_impl::event_more(kernel::event ke) 426 | { 427 | pthread_scoped_lock lk(m_mutex); 428 | m_more_queue.push(ke); 429 | m_cond.signal(); 430 | } 431 | 432 | void loop_impl::event_next(kernel::event ke) 433 | { 434 | m_kernel.reactivate(ke); 435 | } 436 | 437 | void loop_impl::event_remove(kernel::event ke) 438 | { 439 | m_kernel.remove(ke); 440 | reset_handler(ke.ident()); 441 | } 442 | 443 | 444 | } // noname namespace 445 | 446 | 447 | void event::more() 448 | { 449 | event_impl* self = static_cast(this); 450 | if(!self->is_reactivated()) { 451 | self->m_loop->event_more(self->m_pe); 452 | self->m_flags |= 0x01; 453 | } 454 | } 455 | 456 | void event::next() 457 | { 458 | event_impl* self = static_cast(this); 459 | if(!self->is_reactivated()) { 460 | self->m_loop->event_next(self->m_pe); 461 | self->m_flags |= event_impl::FLAG_REACTIVATED; 462 | } 463 | } 464 | 465 | void event::remove() 466 | { 467 | event_impl* self = static_cast(this); 468 | if(!self->is_removed()) { 469 | self->m_loop->event_remove(self->m_pe); 470 | self->m_flags |= event_impl::FLAG_REMOVED; 471 | } 472 | } 473 | 474 | 475 | loop::loop() : m_impl(new loop_impl()) { } 476 | 477 | loop::~loop() { delete ANON_impl; } 478 | 479 | void loop::run(size_t num) 480 | { 481 | start(num); 482 | join(); 483 | } 484 | 485 | void loop::start(size_t num) 486 | { ANON_impl->start(num); } 487 | 488 | bool loop::is_running() const 489 | { return ANON_impl->is_running(); } 490 | 491 | void loop::run_once() 492 | { ANON_impl->run_once(); } 493 | 494 | void loop::run_nonblock() 495 | { ANON_impl->run_nonblock(); } 496 | 497 | void loop::end() 498 | { ANON_impl->end(); } 499 | 500 | bool loop::is_end() const 501 | { return ANON_impl->is_end(); } 502 | 503 | void loop::join() 504 | { ANON_impl->join(); } 505 | 506 | void loop::detach() 507 | { ANON_impl->detach(); } 508 | 509 | void loop::add_thread(size_t num) 510 | { ANON_impl->add_thread(num); } 511 | 512 | shared_handler loop::add_handler_impl(shared_handler newh) 513 | { return ANON_impl->add_handler_impl(newh); } 514 | 515 | void loop::remove_handler(int fd) 516 | { ANON_impl->remove_handler(fd); } 517 | 518 | void loop::submit_impl(task_t f) 519 | { ANON_impl->submit_impl(f); } 520 | 521 | void loop::flush() 522 | { ANON_impl->flush(); } 523 | 524 | } // namespace wavy 525 | } // namespace mp 526 | 527 | -------------------------------------------------------------------------------- /mpsrc/wavy_loop.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio wavy loop 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | #ifndef WAVY_LOOP_H__ 20 | #define WAVY_LOOP_H__ 21 | 22 | #include "jubatus/mp/wavy.h" 23 | #include "jubatus/mp/pthread.h" 24 | #include "wavy_kernel.h" 25 | #include 26 | 27 | namespace mp { 28 | namespace wavy { 29 | namespace { 30 | 31 | 32 | class out; 33 | 34 | 35 | class loop_impl { 36 | public: 37 | loop_impl(function thread_init_func = function()); 38 | ~loop_impl(); 39 | 40 | typedef shared_ptr shared_handler; 41 | typedef function task_t; 42 | 43 | public: 44 | void start(size_t num); 45 | void start(size_t num, size_t max); 46 | 47 | bool is_running() const; 48 | 49 | void end(); 50 | bool is_end() const; 51 | 52 | void run_once(); 53 | void run_nonblock(); 54 | 55 | void run_once(pthread_scoped_lock& lk, bool block = true); 56 | 57 | void join(); 58 | void detach(); 59 | 60 | void add_thread(size_t num); 61 | 62 | shared_handler add_handler_impl(shared_handler sh); 63 | 64 | void remove_handler(int fd); 65 | 66 | void submit_impl(task_t& f); 67 | 68 | void set_handler(shared_handler sh) 69 | { 70 | m_state[sh->ident()] = sh; 71 | } 72 | 73 | void reset_handler(int ident) 74 | { 75 | m_state[ident].reset(); 76 | } 77 | 78 | kernel& get_kernel() 79 | { 80 | return m_kernel; 81 | } 82 | 83 | void flush(); 84 | 85 | public: 86 | void thread_main(); 87 | inline void do_task(pthread_scoped_lock& lk); 88 | inline void do_out(pthread_scoped_lock& lk); 89 | inline void event_more(kernel::event ke); 90 | inline void event_next(kernel::event ke); 91 | inline void event_remove(kernel::event ke); 92 | 93 | private: 94 | volatile size_t m_off; 95 | volatile size_t m_num; 96 | volatile bool m_pollable; 97 | // volatile pthread_t m_poll_thread; // FIXME signal_stop 98 | 99 | kernel::backlog m_backlog; 100 | 101 | shared_handler* m_state; 102 | 103 | kernel m_kernel; 104 | 105 | pthread_mutex m_mutex; 106 | pthread_cond m_cond; 107 | 108 | typedef std::queue task_queue_t; 109 | task_queue_t m_task_queue; 110 | 111 | typedef std::queue more_queue_t; 112 | more_queue_t m_more_queue; 113 | 114 | function m_thread_init_func; 115 | 116 | pthread_cond m_flush_cond; 117 | 118 | private: 119 | shared_ptr m_out; 120 | friend class wavy::loop; 121 | 122 | private: 123 | volatile bool m_end_flag; 124 | 125 | typedef std::vector workers_t; 126 | workers_t m_workers; 127 | 128 | private: 129 | loop_impl(const loop_impl&); 130 | }; 131 | 132 | 133 | #define ANON_impl static_cast(m_impl) 134 | 135 | class event_impl : public event { 136 | public: 137 | event_impl(loop_impl* lo, kernel::event ke) : 138 | m_flags(0), 139 | m_loop(lo), 140 | m_pe(ke) { } 141 | 142 | ~event_impl() { } 143 | 144 | bool is_reactivated() 145 | { 146 | return (m_flags & FLAG_REACTIVATED) != 0; 147 | } 148 | 149 | bool is_removed() 150 | { 151 | return (m_flags & FLAG_REMOVED) != 0; 152 | } 153 | 154 | const kernel::event& get_kernel_event() const 155 | { 156 | return m_pe; 157 | } 158 | 159 | private: 160 | enum { 161 | FLAG_REACTIVATED = 0x01, 162 | FLAG_REMOVED = 0x02, 163 | }; 164 | int m_flags; 165 | loop_impl* m_loop; 166 | kernel::event m_pe; 167 | friend class event; 168 | }; 169 | 170 | 171 | } // noname namespace 172 | } // namespace wavy 173 | } // namespace mp 174 | 175 | #endif /* wavy_loop.h */ 176 | 177 | -------------------------------------------------------------------------------- /mpsrc/wavy_out.cc: -------------------------------------------------------------------------------- 1 | // 2 | // mpio wavy out 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #include "wavy_out.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #if defined(__linux__) || defined(__sun__) 29 | #include 30 | #endif 31 | 32 | namespace mp { 33 | namespace wavy { 34 | namespace { 35 | 36 | 37 | class xfer_impl : public xfer { 38 | public: 39 | xfer_impl() { } 40 | ~xfer_impl() { } 41 | 42 | bool try_write(int fd); 43 | 44 | void push_xfraw(char* buf, size_t size); 45 | 46 | static size_t sizeof_mem(); 47 | static size_t sizeof_iovec(size_t veclen); 48 | static size_t sizeof_sendfile(); 49 | static size_t sizeof_finalize(); 50 | 51 | static char* fill_mem(char* from, const void* buf, size_t size); 52 | static char* fill_iovec(char* from, const struct iovec* vec, size_t veclen); 53 | static char* fill_sendfile(char* from, int infd, uint64_t off, size_t len); 54 | static char* fill_finalize(char* from, finalize_t fin, void* user); 55 | 56 | static bool execute(int fd, char* head, char** tail); 57 | 58 | public: 59 | pthread_mutex& mutex() { return m_mutex; } 60 | 61 | private: 62 | pthread_mutex m_mutex; 63 | 64 | private: 65 | xfer_impl(const xfer_impl&); 66 | }; 67 | 68 | 69 | typedef unsigned int xfer_type; 70 | 71 | static const xfer_type XF_IOVEC = 0; 72 | static const xfer_type XF_SENDFILE = 1; 73 | static const xfer_type XF_FINALIZE = 3; 74 | 75 | struct xfer_sendfile { 76 | int infd; 77 | uint64_t off; 78 | size_t len; 79 | }; 80 | 81 | struct xfer_finalize { 82 | void (*finalize)(void*); 83 | void* user; 84 | }; 85 | 86 | 87 | inline size_t xfer_impl::sizeof_mem() 88 | { 89 | return sizeof(xfer_type) + sizeof(struct iovec)*1; 90 | } 91 | 92 | inline size_t xfer_impl::sizeof_iovec(size_t veclen) 93 | { 94 | return sizeof(xfer_type) + sizeof(iovec) * veclen; 95 | } 96 | 97 | inline size_t xfer_impl::sizeof_sendfile() 98 | { 99 | return sizeof(xfer_type) + sizeof(xfer_sendfile); 100 | } 101 | 102 | inline size_t xfer_impl::sizeof_finalize() 103 | { 104 | return sizeof(xfer_type) + sizeof(xfer_finalize); 105 | } 106 | 107 | inline char* xfer_impl::fill_mem(char* from, const void* buf, size_t size) 108 | { 109 | *(xfer_type*)from = 1 << 1; 110 | from += sizeof(xfer_type); 111 | 112 | ((struct iovec*)from)->iov_base = const_cast(buf); 113 | ((struct iovec*)from)->iov_len = size; 114 | from += sizeof(struct iovec); 115 | 116 | return from; 117 | } 118 | 119 | inline char* xfer_impl::fill_iovec(char* from, const struct iovec* vec, size_t veclen) 120 | { 121 | *(xfer_type*)from = veclen << 1; 122 | from += sizeof(xfer_type); 123 | 124 | const size_t iovbufsz = sizeof(struct iovec) * veclen; 125 | memcpy(from, vec, iovbufsz); 126 | from += iovbufsz; 127 | 128 | return from; 129 | } 130 | 131 | inline char* xfer_impl::fill_sendfile(char* from, int infd, uint64_t off, size_t len) 132 | { 133 | *(xfer_type*)from = XF_SENDFILE; 134 | from += sizeof(xfer_type); 135 | 136 | ((xfer_sendfile*)from)->infd = infd; 137 | ((xfer_sendfile*)from)->off = off; 138 | ((xfer_sendfile*)from)->len = len; 139 | from += sizeof(xfer_sendfile); 140 | 141 | return from; 142 | } 143 | 144 | inline char* xfer_impl::fill_finalize(char* from, finalize_t fin, void* user) 145 | { 146 | *(xfer_type*)from = XF_FINALIZE; 147 | from += sizeof(xfer_type); 148 | 149 | ((xfer_finalize*)from)->finalize = fin; 150 | ((xfer_finalize*)from)->user = user; 151 | from += sizeof(xfer_finalize); 152 | 153 | return from; 154 | } 155 | 156 | void xfer_impl::push_xfraw(char* buf, size_t size) 157 | { 158 | if(m_free < size) { reserve(size); } 159 | memcpy(m_tail, buf, size); 160 | m_tail += size; 161 | m_free -= size; 162 | } 163 | 164 | 165 | #define MP_WAVY_XFER_CONSUMED \ 166 | do { \ 167 | size_t left = endp - p; \ 168 | ::memmove(head, p, left); \ 169 | *tail = head + left; \ 170 | } while(0) 171 | 172 | bool xfer_impl::execute(int fd, char* head, char** tail) 173 | { 174 | char* p = head; 175 | char* const endp = *tail; 176 | while(p < endp) { 177 | switch(*(xfer_type*)p) { 178 | case XF_SENDFILE: { 179 | xfer_sendfile* x = (xfer_sendfile*)(p + sizeof(xfer_type)); 180 | #if defined(__linux__) || defined(__sun__) 181 | off_t off = x->off; 182 | ssize_t wl = ::sendfile(fd, x->infd, &off, x->len); 183 | if(wl <= 0) { 184 | MP_WAVY_XFER_CONSUMED; 185 | if(wl < 0 && (errno == EAGAIN || errno == EINTR)) { 186 | return true; 187 | } else { 188 | return false; 189 | } 190 | } 191 | #elif defined(__APPLE__) && defined(__MACH__) 192 | off_t wl = x->len; 193 | if(::sendfile(x->infd, fd, x->off, &wl, NULL, 0) < 0) { 194 | MP_WAVY_XFER_CONSUMED; 195 | if(errno == EAGAIN || errno == EINTR) { 196 | return true; 197 | } else { 198 | return false; 199 | } 200 | } 201 | #else 202 | off_t sbytes = 0; 203 | if(::sendfile(x->infd, fd, x->off, x->len, NULL, &sbytes, 0) < 0) { 204 | MP_WAVY_XFER_CONSUMED; 205 | if(errno == EAGAIN || errno == EINTR) { 206 | return true; 207 | } else { 208 | return false; 209 | } 210 | } 211 | off_t wl = x->len + sbytes; 212 | #endif 213 | 214 | if(static_cast(wl) < x->len) { 215 | x->off += wl; 216 | x->len -= wl; 217 | MP_WAVY_XFER_CONSUMED; 218 | return true; 219 | } 220 | 221 | p += sizeof_sendfile(); 222 | break; } 223 | 224 | case XF_FINALIZE: { 225 | xfer_finalize* x = (xfer_finalize*)(p + sizeof(xfer_type)); 226 | if(x->finalize) try { 227 | x->finalize(x->user); 228 | } catch (...) { } 229 | 230 | p += xfer_impl::sizeof_finalize(); 231 | break; } 232 | 233 | default: { // XF_IOVEC 234 | size_t veclen = (*(xfer_type*)p) >> 1; 235 | struct iovec* vec = (struct iovec*)(p + sizeof(xfer_type)); 236 | 237 | ssize_t wl = ::writev(fd, vec, veclen); 238 | if(wl <= 0) { 239 | MP_WAVY_XFER_CONSUMED; 240 | if(wl < 0 && (errno == EAGAIN || errno == EINTR)) { 241 | return true; 242 | } else { 243 | return false; 244 | } 245 | } 246 | 247 | for(size_t i=0; i < veclen; ++i) { 248 | if(static_cast(wl) >= vec[i].iov_len) { 249 | wl -= vec[i].iov_len; 250 | } else { 251 | vec[i].iov_base = (void*)(((char*)vec[i].iov_base) + wl); 252 | vec[i].iov_len -= wl; 253 | 254 | if(i == 0) { 255 | MP_WAVY_XFER_CONSUMED; 256 | } else { 257 | p += sizeof_iovec(veclen); 258 | size_t left = endp - p; 259 | char* filltail = fill_iovec(head, vec+i, veclen-i); 260 | ::memmove(filltail, p, left); 261 | *tail = filltail + left; 262 | } 263 | 264 | return true; 265 | } 266 | } 267 | 268 | p += sizeof_iovec(veclen); 269 | 270 | break; } 271 | } 272 | } 273 | 274 | *tail = head; 275 | return false; 276 | } 277 | 278 | 279 | bool xfer_impl::try_write(int fd) 280 | { 281 | char* const alloc_end = m_tail + m_free; 282 | bool cont = execute(fd, m_head, &m_tail); 283 | m_free = alloc_end - m_tail; 284 | 285 | if(!cont && !empty()) { 286 | // error occured 287 | ::shutdown(fd, SHUT_RD); 288 | } 289 | return cont; 290 | } 291 | 292 | 293 | } // noname namespace 294 | 295 | 296 | void xfer::reserve(size_t reqsz) 297 | { 298 | size_t used = m_tail - m_head; 299 | reqsz += used; 300 | size_t nsize = (used + m_free) * 2 + 72; // used + m_free may be 0 301 | 302 | while(nsize < reqsz) { nsize *= 2; } 303 | 304 | char* tmp = (char*)::realloc(m_head, nsize); 305 | if(!tmp) { throw std::bad_alloc(); } 306 | 307 | m_head = tmp; 308 | m_tail = tmp + used; 309 | m_free = nsize - used; 310 | } 311 | 312 | 313 | void xfer::push_write(const void* buf, size_t size) 314 | { 315 | size_t sz = xfer_impl::sizeof_mem(); 316 | if(m_free < sz) { reserve(sz); } 317 | m_tail = xfer_impl::fill_mem(m_tail, buf, size); 318 | m_free -= sz; 319 | } 320 | 321 | void xfer::push_writev(const struct iovec* vec, size_t veclen) 322 | { 323 | size_t sz = xfer_impl::sizeof_iovec(veclen); 324 | if(m_free < sz) { reserve(sz); } 325 | m_tail = xfer_impl::fill_iovec(m_tail, vec, veclen); 326 | m_free -= sz; 327 | } 328 | 329 | void xfer::push_sendfile(int infd, uint64_t off, size_t len) 330 | { 331 | size_t sz = xfer_impl::sizeof_sendfile(); 332 | if(m_free < sz) { reserve(sz); } 333 | m_tail = xfer_impl::fill_sendfile(m_tail, infd, off, len); 334 | m_free -= sz; 335 | } 336 | 337 | void xfer::push_finalize(finalize_t fin, void* user) 338 | { 339 | size_t sz = xfer_impl::sizeof_finalize(); 340 | if(m_free < sz) { reserve(sz); } 341 | m_tail = xfer_impl::fill_finalize(m_tail, fin, user); 342 | m_free -= sz; 343 | } 344 | 345 | void xfer::migrate(xfer* to) 346 | { 347 | if(to->m_head == NULL) { 348 | // swap 349 | to->m_head = m_head; 350 | to->m_tail = m_tail; 351 | to->m_free = m_free; 352 | m_tail = m_head = NULL; 353 | m_free = 0; 354 | return; 355 | } 356 | 357 | size_t reqsz = m_tail - m_head; 358 | if(to->m_free < reqsz) { to->reserve(reqsz); } 359 | 360 | memcpy(to->m_tail, m_head, reqsz); 361 | to->m_tail += reqsz; 362 | to->m_free -= reqsz; 363 | 364 | m_free += reqsz; 365 | m_tail = m_head; 366 | } 367 | 368 | void xfer::clear() 369 | { 370 | for(char* p = m_head; p < m_tail; ) { 371 | switch(*(xfer_type*)p) { 372 | case XF_SENDFILE: 373 | p += xfer_impl::sizeof_sendfile(); 374 | break; 375 | 376 | case XF_FINALIZE: { 377 | xfer_finalize* x = (xfer_finalize*)(p + sizeof(xfer_type)); 378 | if(x->finalize) try { 379 | x->finalize(x->user); 380 | } catch (...) { } 381 | 382 | p += xfer_impl::sizeof_finalize(); 383 | break; } 384 | 385 | default: // XF_IOVEC 386 | p += xfer_impl::sizeof_iovec( (*(xfer_type*)p) >> 1 ); 387 | break; 388 | } 389 | } 390 | 391 | //::free(m_head); 392 | //m_tail = m_head = NULL; 393 | //m_free = 0; 394 | m_free += m_tail - m_head; 395 | m_tail = m_head; 396 | } 397 | 398 | 399 | #define ANON_fdctx reinterpret_cast(m_fdctx) 400 | 401 | out::out() : basic_handler(m_kernel.ident(), this), m_watching(0) 402 | { 403 | struct rlimit rbuf; 404 | if(::getrlimit(RLIMIT_NOFILE, &rbuf) < 0) { 405 | throw system_error(errno, "getrlimit() failed"); 406 | } 407 | m_fdctx = new xfer_impl[rbuf.rlim_cur]; 408 | } 409 | 410 | out::~out() 411 | { 412 | delete[] ANON_fdctx; 413 | } 414 | 415 | void out::poll_event() 416 | { 417 | int num = m_kernel.wait(&m_backlog, 0); 418 | if(num <= 0) { 419 | if(num == 0 || errno == EINTR || errno == EAGAIN) { 420 | return; 421 | } else { 422 | throw system_error(errno, "wavy out event failed"); 423 | } 424 | } 425 | 426 | for(int i=0; i < num; ++i) { 427 | m_queue.push(m_backlog[i]); 428 | } 429 | } 430 | 431 | bool out::write_event(kernel::event e) 432 | { 433 | int ident = e.ident(); 434 | 435 | xfer_impl& ctx(ANON_fdctx[ident]); 436 | pthread_scoped_lock lk(ctx.mutex()); 437 | 438 | bool cont; 439 | try { 440 | cont = ctx.try_write(ident); 441 | } catch (...) { 442 | cont = false; 443 | } 444 | 445 | if(!cont) { 446 | m_kernel.remove(e); 447 | ctx.clear(); 448 | return __sync_sub_and_fetch(&m_watching, 1) == 0; 449 | } else { 450 | m_kernel.reactivate(e); 451 | return false; 452 | } 453 | } 454 | 455 | inline void out::watch(int fd) 456 | { 457 | m_kernel.add_fd(fd, EVKERNEL_WRITE); 458 | __sync_add_and_fetch(&m_watching, 1); 459 | } 460 | 461 | 462 | void out::commit_raw(int fd, char* xfbuf, char* xfendp) 463 | { 464 | xfer_impl& ctx(ANON_fdctx[fd]); 465 | pthread_scoped_lock lk(ctx.mutex()); 466 | 467 | if(!ctx.empty()) { 468 | ctx.push_xfraw(xfbuf, xfendp - xfbuf); 469 | return; 470 | } 471 | 472 | if(xfer_impl::execute(fd, xfbuf, &xfendp)) { 473 | ctx.push_xfraw(xfbuf, xfendp - xfbuf); // FIXME exception 474 | watch(fd); // FIXME exception 475 | } 476 | } 477 | 478 | void out::commit(int fd, xfer* xf) 479 | { 480 | xfer_impl& ctx(ANON_fdctx[fd]); 481 | pthread_scoped_lock lk(ctx.mutex()); 482 | 483 | if(!ctx.empty()) { 484 | xf->migrate(&ctx); 485 | return; 486 | } 487 | 488 | if(static_cast(xf)->try_write(fd)) { 489 | xf->migrate(&ctx); // FIXME exception 490 | watch(fd); // FIXME exception 491 | } 492 | } 493 | 494 | void out::write(int fd, const void* buf, size_t size) 495 | { 496 | xfer_impl& ctx(ANON_fdctx[fd]); 497 | pthread_scoped_lock lk(ctx.mutex()); 498 | 499 | if(ctx.empty()) { 500 | ssize_t wl = ::write(fd, buf, size); 501 | if(wl <= 0) { 502 | if(wl == 0 || (errno != EINTR && errno != EAGAIN)) { 503 | ::shutdown(fd, SHUT_RD); 504 | return; 505 | } 506 | } else if(static_cast(wl) >= size) { 507 | return; 508 | } else { 509 | buf = ((const char*)buf) + wl; 510 | size -= wl; 511 | } 512 | 513 | ctx.push_write(buf, size); 514 | watch(fd); 515 | 516 | } else { 517 | ctx.push_write(buf, size); 518 | } 519 | } 520 | 521 | void out::clear_xfer(int fd) 522 | { 523 | xfer_impl& ctx(ANON_fdctx[fd]); 524 | pthread_scoped_lock lk(ctx.mutex()); 525 | 526 | ctx.clear(); 527 | } 528 | 529 | 530 | #define ANON_out static_cast(m_impl)->m_out 531 | 532 | void loop::commit(int fd, xfer* xf) 533 | { ANON_out->commit(fd, xf); } 534 | 535 | void loop::write(int fd, const void* buf, size_t size) 536 | { ANON_out->write(fd, buf, size); } 537 | 538 | void loop::write(int fd, 539 | const void* buf, size_t size, 540 | finalize_t fin, void* user) 541 | { 542 | char xfbuf[ xfer_impl::sizeof_mem() + xfer_impl::sizeof_finalize() ]; 543 | char* p = xfbuf; 544 | p = xfer_impl::fill_mem(p, buf, size); 545 | p = xfer_impl::fill_finalize(p, fin, user); 546 | ANON_out->commit_raw(fd, xfbuf, p); 547 | } 548 | 549 | void loop::writev(int fd, 550 | const struct iovec* vec, size_t veclen, 551 | finalize_t fin, void* user) 552 | { 553 | char xfbuf[ xfer_impl::sizeof_iovec(veclen) + xfer_impl::sizeof_finalize() ]; 554 | char* p = xfbuf; 555 | p = xfer_impl::fill_iovec(p, vec, veclen); 556 | p = xfer_impl::fill_finalize(p, fin, user); 557 | ANON_out->commit_raw(fd, xfbuf, p); 558 | } 559 | 560 | void loop::sendfile(int fd, 561 | int infd, uint64_t off, size_t size, 562 | finalize_t fin, void* user) 563 | { 564 | char xfbuf[ xfer_impl::sizeof_sendfile() + xfer_impl::sizeof_finalize() ]; 565 | char* p = xfbuf; 566 | p = xfer_impl::fill_sendfile(p, infd, off, size); 567 | p = xfer_impl::fill_finalize(p, fin, user); 568 | ANON_out->commit_raw(fd, xfbuf, p); 569 | } 570 | 571 | void loop::hsendfile(int fd, 572 | const void* header, size_t header_size, 573 | int infd, uint64_t off, size_t size, 574 | finalize_t fin, void* user) 575 | { 576 | char xfbuf[ xfer_impl::sizeof_mem() 577 | + xfer_impl::sizeof_sendfile() + xfer_impl::sizeof_finalize() ]; 578 | char* p = xfbuf; 579 | p = xfer_impl::fill_mem(p, header, header_size); 580 | p = xfer_impl::fill_sendfile(p, infd, off, size); 581 | p = xfer_impl::fill_finalize(p, fin, user); 582 | ANON_out->commit_raw(fd, xfbuf, p); 583 | } 584 | 585 | void loop::hvsendfile(int fd, 586 | const struct iovec* header_vec, size_t header_veclen, 587 | int infd, uint64_t off, size_t size, 588 | finalize_t fin, void* user) 589 | { 590 | char xfbuf[ xfer_impl::sizeof_iovec(header_veclen) 591 | + xfer_impl::sizeof_sendfile() + xfer_impl::sizeof_finalize() ]; 592 | char* p = xfbuf; 593 | p = xfer_impl::fill_iovec(p, header_vec, header_veclen); 594 | p = xfer_impl::fill_sendfile(p, infd, off, size); 595 | p = xfer_impl::fill_finalize(p, fin, user); 596 | ANON_out->commit_raw(fd, xfbuf, p); 597 | } 598 | 599 | 600 | } // namespace wavy 601 | } // namespace mp 602 | 603 | -------------------------------------------------------------------------------- /mpsrc/wavy_out.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio wavy out 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #ifndef WAVY_OUT_H__ 19 | #define WAVY_OUT_H__ 20 | 21 | #include "wavy_loop.h" 22 | 23 | namespace mp { 24 | namespace wavy { 25 | namespace { 26 | 27 | 28 | struct kernel_mixin { 29 | kernel m_kernel; 30 | }; 31 | 32 | 33 | class out : protected kernel_mixin, public basic_handler { 34 | public: 35 | out(); 36 | ~out(); 37 | 38 | typedef loop::finalize_t finalize_t; 39 | 40 | inline void commit_raw(int fd, char* xfbuf, char* xfendp); 41 | 42 | // optimize 43 | inline void commit(int fd, xfer* xf); 44 | inline void write(int fd, const void* buf, size_t size); 45 | 46 | inline void clear_xfer(int fd); 47 | 48 | public: 49 | kernel& get_kernel() 50 | { 51 | return m_kernel; 52 | } 53 | 54 | bool operator() (event& e) 55 | { 56 | throw std::logic_error("out::on_read is called"); 57 | } 58 | 59 | bool has_queue() const 60 | { 61 | return !m_queue.empty(); 62 | } 63 | 64 | void poll_event(); 65 | 66 | bool write_event(kernel::event e); 67 | 68 | kernel::event next() 69 | { 70 | kernel::event e = m_queue.front(); 71 | m_queue.pop(); 72 | return e; 73 | } 74 | 75 | bool empty() const 76 | { 77 | return m_watching == 0; 78 | } 79 | 80 | private: 81 | std::queue m_queue; 82 | kernel::backlog m_backlog; 83 | volatile int m_watching; 84 | 85 | void watch(int fd); 86 | void* m_fdctx; 87 | 88 | private: 89 | out(const out&); 90 | }; 91 | 92 | 93 | } // noname namespace 94 | } // namespace wavy 95 | } // namespace mp 96 | 97 | #endif /* wavy_out.h */ 98 | 99 | -------------------------------------------------------------------------------- /mpsrc/wavy_signal.cc: -------------------------------------------------------------------------------- 1 | // 2 | // mpio wavy signal 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #ifndef DISABLE_SIGNALFD 19 | #include "wavy_signal.h" 20 | 21 | namespace mp { 22 | namespace wavy { 23 | 24 | 25 | int loop::add_signal(int signo, function callback) 26 | { 27 | kernel& kern(ANON_impl->get_kernel()); 28 | 29 | shared_handler sh(new signal_handler(kern, signo, callback)); 30 | ANON_impl->set_handler(sh); 31 | 32 | return sh->ident(); 33 | } 34 | 35 | 36 | void loop::remove_signal(int ident) 37 | { 38 | kernel& kern(ANON_impl->get_kernel()); 39 | kern.remove_signal(ident); 40 | ANON_impl->reset_handler(ident); // FIXME? 41 | } 42 | 43 | 44 | } // namespace wavy 45 | } // namespace mp 46 | #endif 47 | 48 | -------------------------------------------------------------------------------- /mpsrc/wavy_signal.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio wavy signal 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | #ifndef DISABLE_SIGNALFD 20 | #ifndef WAVY_SIGNAL_H__ 21 | #define WAVY_SIGNAL_H__ 22 | 23 | #include "wavy_loop.h" 24 | #include "jubatus/mp/signal.h" 25 | #include 26 | 27 | namespace mp { 28 | namespace wavy { 29 | namespace { 30 | 31 | 32 | struct kernel_signal { 33 | kernel_signal(kernel& kern, int signo) 34 | { 35 | if(kern.add_signal(&m_signal, signo) < 0) { 36 | throw system_error(errno, "failed to create signal event"); 37 | } 38 | } 39 | 40 | ~kernel_signal() { } 41 | 42 | protected: 43 | int signal_ident() const 44 | { 45 | return m_signal.ident(); 46 | } 47 | 48 | int read_signal(event& e) 49 | { 50 | return kernel::read_signal( static_cast(e).get_kernel_event() ); 51 | } 52 | 53 | private: 54 | kernel::signal m_signal; 55 | 56 | private: 57 | kernel_signal(); 58 | kernel_signal(const kernel_signal&); 59 | }; 60 | 61 | 62 | class signal_handler : public kernel_signal, public basic_handler { 63 | public: 64 | signal_handler(kernel& kern, int signo, 65 | function callback) : 66 | kernel_signal(kern, signo), 67 | basic_handler(signal_ident(), this), 68 | m_signo(signo), m_callback(callback), 69 | m_signal(signo, SIG_IGN), 70 | m_sigmask(sigset().add(signo)) 71 | { } 72 | 73 | ~signal_handler() { } 74 | 75 | bool operator() (event& e) 76 | { 77 | read_signal(e); 78 | return m_callback(); 79 | } 80 | 81 | private: 82 | int m_signo; 83 | function m_callback; 84 | scoped_signal m_signal; 85 | scoped_sigprocmask m_sigmask; 86 | }; 87 | 88 | 89 | } // noname namespace 90 | } // namespace wavy 91 | } // namespace mp 92 | 93 | #endif /* wavy_signal.h */ 94 | #endif 95 | 96 | -------------------------------------------------------------------------------- /mpsrc/wavy_timer.cc: -------------------------------------------------------------------------------- 1 | // 2 | // mpio wavy timer 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #include "wavy_timer.h" 19 | 20 | namespace mp { 21 | namespace wavy { 22 | 23 | 24 | int loop::add_timer(const timespec* value, const timespec* interval, 25 | function callback) 26 | { 27 | kernel& kern(ANON_impl->get_kernel()); 28 | 29 | shared_handler sh(new timer_handler(kern, value, interval, callback)); 30 | ANON_impl->set_handler(sh); 31 | 32 | return sh->ident(); 33 | } 34 | 35 | 36 | static inline struct timespec sec2spec(double sec) 37 | { 38 | struct timespec spec = { 39 | static_cast(sec), 40 | static_cast((sec - (double)(long)sec) * 1e9) }; 41 | return spec; 42 | } 43 | 44 | int loop::add_timer(double value_sec, double interval_sec, 45 | function callback) 46 | { 47 | if(value_sec >= 0.0) { 48 | if(interval_sec > 0.0) { 49 | struct timespec value = sec2spec(value_sec); 50 | struct timespec interval = sec2spec(interval_sec); 51 | return add_timer(&value, &interval, callback); 52 | } else { 53 | struct timespec value = sec2spec(value_sec); 54 | return add_timer(&value, NULL, callback); 55 | } 56 | } else { 57 | if(interval_sec > 0.0) { 58 | struct timespec interval = sec2spec(interval_sec); 59 | return add_timer(NULL, &interval, callback); 60 | } else { 61 | // FIXME ambiguous overload 62 | return add_timer(NULL, (const timespec*)NULL, callback); 63 | } 64 | } 65 | } 66 | 67 | 68 | void loop::remove_timer(int ident) 69 | { 70 | ANON_impl->reset_handler(ident); 71 | kernel& kern(ANON_impl->get_kernel()); 72 | kern.remove_timer(ident); // FIXME? 73 | } 74 | 75 | 76 | } // namespace wavy 77 | } // namespace mp 78 | 79 | -------------------------------------------------------------------------------- /mpsrc/wavy_timer.h: -------------------------------------------------------------------------------- 1 | // 2 | // mpio wavy timer 3 | // 4 | // Copyright (C) 2008-2010 FURUHASHI Sadayuki 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | #ifndef WAVY_TIMER_H__ 19 | #define WAVY_TIMER_H__ 20 | 21 | #include "wavy_loop.h" 22 | #include 23 | 24 | namespace mp { 25 | namespace wavy { 26 | namespace { 27 | 28 | 29 | struct kernel_timer { 30 | kernel_timer(kernel& kern, const timespec* value, const timespec* interval) 31 | { 32 | if(kern.add_timer(&m_timer, value, interval) < 0) { 33 | throw system_error(errno, "failed to create timer event"); 34 | } 35 | } 36 | 37 | ~kernel_timer() { } 38 | 39 | protected: 40 | int timer_ident() const 41 | { 42 | return m_timer.ident(); 43 | } 44 | 45 | int read_timer(event& e) 46 | { 47 | return kernel::read_timer( static_cast(e).get_kernel_event() ); 48 | } 49 | 50 | private: 51 | kernel::timer m_timer; 52 | 53 | private: 54 | kernel_timer(); 55 | kernel_timer(const kernel_timer&); 56 | }; 57 | 58 | 59 | class timer_handler : public kernel_timer, public basic_handler { 60 | public: 61 | timer_handler(kernel& kern, const timespec* value, const timespec* interval, 62 | function callback) : 63 | kernel_timer(kern, value, interval), 64 | basic_handler(timer_ident(), this), 65 | m_periodic(interval && (interval->tv_sec != 0 || interval->tv_nsec != 0)), 66 | m_callback(callback) 67 | { } 68 | 69 | ~timer_handler() { } 70 | 71 | bool operator() (event& e) 72 | { 73 | read_timer(e); 74 | return m_callback() && m_periodic; 75 | } 76 | 77 | private: 78 | bool m_periodic; 79 | function m_callback; 80 | }; 81 | 82 | 83 | } // noname namespace 84 | } // namespace wavy 85 | } // namespace mp 86 | 87 | #endif /* wavy_timer.h */ 88 | 89 | -------------------------------------------------------------------------------- /preprocess: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 4 | 5 | RUBY="ruby" 6 | 7 | function r() { 8 | echo "$@" 9 | "$@" 10 | } 11 | 12 | function preprocess() { 13 | file="$1" 14 | out="$(dirname "$file")/$(basename "$file" mpl)" 15 | r "$RUBY" -I. mplex -rmpl "$file" -o "$out" 16 | if [ "$?" != 0 ]; then 17 | echo "" 18 | echo "** preprocess failed **" 19 | echo "" 20 | exit 1 21 | fi 22 | } 23 | 24 | preprocess jubatus/mp/object_callback.hmpl 25 | preprocess jubatus/mp/sparse_array.hmpl 26 | preprocess jubatus/mp/sync.hmpl 27 | preprocess jubatus/mp/wavy.hmpl 28 | 29 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 2 | 3 | AM_CPPFLAGS = -I.. 4 | AM_C_CPPFLAGS = -I.. 5 | AM_LDFLAGS = ../mpsrc/libjubatus_mpio.la 6 | 7 | check_PROGRAMS = \ 8 | listen_connect \ 9 | handler \ 10 | signal \ 11 | timer \ 12 | many_timer \ 13 | sync \ 14 | huge_message 15 | 16 | TESTS = $(check_PROGRAMS) 17 | 18 | listen_connect_SOURCES = listen_connect.cc 19 | 20 | handler_SOURCES = handler.cc 21 | 22 | signal_SOURCES = signal.cc 23 | 24 | timer_SOURCES = timer.cc 25 | 26 | many_timer_SOURCES = many_timer.cc 27 | 28 | sync_SOURCES = sync.cc 29 | 30 | huge_message_SOURCES = huge_message.cc 31 | -------------------------------------------------------------------------------- /test/handler.cc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace mp::placeholders; 13 | 14 | class handler : public mp::wavy::handler { 15 | public: 16 | handler(int fd, mp::wavy::loop* lo) : 17 | mp::wavy::handler(fd), 18 | m_lo(lo), 19 | m_count(0) { } 20 | 21 | void on_read(mp::wavy::event& e) 22 | { 23 | char buf[512]; 24 | ssize_t rl = read(fd(), buf, sizeof(buf)); 25 | if(rl <= 0) { 26 | if(rl == 0) { 27 | throw mp::system_error(errno, "connection closed"); 28 | } 29 | if(errno == EINTR || errno == EAGAIN) { return; } 30 | } 31 | 32 | std::cout << "read "<end(); 37 | } 38 | 39 | private: 40 | mp::wavy::loop* m_lo; 41 | int m_count; 42 | }; 43 | 44 | bool timer_handler(int* count, mp::wavy::loop* lo) 45 | { 46 | std::cout << "timer" << std::endl; 47 | 48 | if(++(*count) >= 3) { 49 | lo->end(); 50 | return false; 51 | } 52 | 53 | return true; 54 | } 55 | 56 | void my_function() 57 | { 58 | std::cout << "ok" << std::endl; 59 | } 60 | 61 | void reader_main(int rpipe) 62 | { 63 | mp::wavy::loop lo; 64 | 65 | lo.add_handler(rpipe, &lo); 66 | 67 | int count = 0; 68 | lo.add_timer(0.1, 0.1, mp::bind( 69 | &timer_handler, &count, &lo)); 70 | 71 | lo.submit(&my_function); 72 | 73 | lo.run(4); 74 | } 75 | 76 | void writer_main(int wpipe) 77 | { 78 | mp::wavy::loop lo; 79 | 80 | for(int i=0; i < 15; ++i) { 81 | lo.write(wpipe, "test", 4); 82 | } 83 | 84 | lo.flush(); 85 | } 86 | 87 | int main(void) 88 | { 89 | int pair[2]; 90 | pipe(pair); 91 | 92 | pid_t pid = fork(); 93 | if(pid == 0) { 94 | reader_main(pair[0]); 95 | exit(0); 96 | } 97 | 98 | writer_main(pair[1]); 99 | 100 | wait(NULL); 101 | } 102 | 103 | -------------------------------------------------------------------------------- /test/huge_message.cc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace mp::placeholders; 15 | 16 | size_t total_write_size = 1024*1024*128; // KByte 17 | 18 | typedef std::vector buffer_t; 19 | 20 | class server_handler: public mp::wavy::handler { 21 | public: 22 | server_handler(int fd, mp::wavy::loop *lo) : 23 | mp::wavy::handler(fd), 24 | loop_(lo) {} 25 | 26 | void on_read(mp::wavy::event& ev) { 27 | buffer_t rbuf(1024); 28 | ssize_t read_size = ::read(fd(), &rbuf[0], rbuf.size()); 29 | if ( read_size < 0 ) { 30 | perror("read error"); 31 | exit(1); 32 | } else if ( read_size == 0 ) { 33 | ev.remove(); 34 | return; 35 | } 36 | 37 | std::auto_ptr buf( new buffer_t(total_write_size) ); 38 | loop_->write(fd(), &((*buf)[0]), buf->size(), buf); 39 | std::cerr << "wrote " << total_write_size << "bytes" 40 | << std::endl; 41 | } 42 | static void accepted(mp::wavy::loop *lo, int fd, int err) { 43 | if(fd < 0) { 44 | errno = err; 45 | perror("accept error"); 46 | exit(1); 47 | } 48 | 49 | try { 50 | std::cerr << "accepted. " << std::endl; 51 | lo->add_handler(fd, lo); 52 | 53 | } catch(...) { 54 | throw; 55 | } 56 | } 57 | 58 | private: 59 | mp::wavy::loop *loop_; 60 | }; 61 | 62 | class client_handler: public mp::wavy::handler { 63 | public: 64 | client_handler(int fd, mp::wavy::loop *lo) : 65 | mp::wavy::handler(fd), 66 | loop_(lo), 67 | buf_(1024*1024), 68 | total_size_(0) { } 69 | 70 | void on_read(mp::wavy::event& ev) { 71 | ssize_t read_size = read( fd(), &buf_[0], buf_.size()); 72 | std::cerr << "." << std::flush; 73 | 74 | if ( read_size <= 0 ) { 75 | std::cerr << std::endl 76 | << "session closed with " << read_size 77 | << std::endl; 78 | 79 | ev.remove(); 80 | loop_->end(); 81 | exit(1); 82 | } 83 | total_size_ += read_size; 84 | 85 | if ( total_size_ == total_write_size ) { 86 | std::cerr << std::endl << "OK" << std::endl; 87 | ev.remove(); 88 | loop_->end(); 89 | return; 90 | } 91 | } 92 | 93 | static void connected(mp::wavy::loop *lo, int fd, int err) { 94 | if ( fd < 0 ) { 95 | errno = err; 96 | perror("connect error"); 97 | exit(1); 98 | } 99 | 100 | try { 101 | std::cerr << "connected" << std::endl; 102 | 103 | buffer_t buf(32); 104 | if ( ::write(fd, &buf[0], buf.size()) < 0 ) { 105 | perror("write error"); 106 | exit(1); 107 | } 108 | 109 | lo->add_handler(fd, lo); 110 | lo->add_timer( 10.0, 0.0, 111 | mp::bind( &client_handler::on_timed_out, 112 | lo)); 113 | } catch(...) { 114 | ::close(fd); 115 | throw; 116 | } 117 | } 118 | 119 | static bool on_timed_out(mp::wavy::loop *lo) { 120 | lo->end(); 121 | std::cerr << "timeout" << std::endl; 122 | exit(1); 123 | return false; 124 | } 125 | 126 | private: 127 | mp::wavy::loop *loop_; 128 | std::vector buf_; 129 | size_t total_size_; 130 | }; 131 | 132 | int main(int argc, char **argv) 133 | { 134 | std::string host = "127.0.0.1"; 135 | int port = 9090; 136 | if ( argv[1] ) { 137 | host = argv[1]; 138 | if ( argv[2] ) port = strtoul( argv[2], NULL, 10); 139 | } 140 | 141 | mp::wavy::loop lo_server; 142 | 143 | struct sockaddr_in addr; 144 | memset(&addr, 0, sizeof(addr)); 145 | addr.sin_port = htons(port); 146 | addr.sin_family = AF_INET; 147 | addr.sin_addr.s_addr = htonl(INADDR_ANY); 148 | 149 | lo_server.listen(PF_INET, SOCK_STREAM, 0, 150 | (struct sockaddr*)&addr, sizeof(addr), 151 | mp::bind(&server_handler::accepted, 152 | &lo_server, _1, _2)); 153 | 154 | lo_server.start(1); // run with 1 threads 155 | 156 | mp::wavy::loop lo_client; 157 | lo_client.start(2); // run with 2 threads 158 | 159 | addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 160 | lo_client.connect(PF_INET, SOCK_STREAM, 0, 161 | (struct sockaddr*)&addr, sizeof(addr), 162 | 0.0, 163 | mp::bind(&client_handler::connected, 164 | &lo_client, _1, _2)); 165 | 166 | lo_client.join(); 167 | lo_server.end(); 168 | lo_server.join(); 169 | 170 | return 0; 171 | } 172 | -------------------------------------------------------------------------------- /test/listen_connect.cc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace mp::placeholders; 8 | 9 | void accepted(int fd, int err) 10 | { 11 | if(fd < 0) { 12 | errno = err; 13 | perror("accept error"); 14 | return; 15 | } 16 | 17 | try { 18 | std::cout << "accepted" << std::endl; 19 | 20 | // do something with fd 21 | close(fd); 22 | 23 | } catch (...) { 24 | ::close(fd); 25 | return; 26 | } 27 | } 28 | 29 | void connected(int fd, int err) 30 | { 31 | if(fd < 0) { 32 | errno = err; 33 | perror("connect error"); 34 | return; 35 | } 36 | 37 | try { 38 | std::cout << "connected" << std::endl; 39 | 40 | // do something with fd 41 | 42 | } catch (...) { } 43 | ::close(fd); 44 | } 45 | 46 | int main(void) 47 | { 48 | mp::wavy::loop lo; 49 | 50 | struct sockaddr_in addr; 51 | memset(&addr, 0, sizeof(addr)); 52 | addr.sin_port = htons(9090); 53 | addr.sin_family = AF_INET; 54 | addr.sin_addr.s_addr = htonl(INADDR_ANY); 55 | 56 | lo.listen(PF_INET, SOCK_STREAM, 0, 57 | (struct sockaddr*)&addr, sizeof(addr), 58 | mp::bind(&accepted, _1, _2)); 59 | 60 | lo.start(4); // run with 4 threads 61 | 62 | { 63 | addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 64 | lo.connect(PF_INET, SOCK_STREAM, 0, 65 | (struct sockaddr*)&addr, sizeof(addr), 66 | 0.0, connected); 67 | } 68 | 69 | usleep(50*1e3); 70 | 71 | lo.end(); 72 | lo.join(); 73 | } 74 | 75 | -------------------------------------------------------------------------------- /test/many_timer.cc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace mp::placeholders; 11 | 12 | bool timer_handler(int* count, mp::wavy::loop* lo) 13 | { 14 | try { 15 | std::cout << "*" << std::flush; 16 | if(--(*count) < 0) { 17 | lo->end(); 18 | } 19 | else { 20 | lo->add_timer(0.001, 0, mp::bind(&timer_handler, count, lo)); 21 | } 22 | return false; 23 | } 24 | catch (std::exception& e) { 25 | std::cerr << e.what() << std::endl; 26 | std::exit(1); 27 | } 28 | } 29 | 30 | int main(void) 31 | { 32 | mp::wavy::loop lo; 33 | int count = 2000; 34 | lo.add_timer(0.01, 0, mp::bind( 35 | &timer_handler, &count, &lo)); 36 | lo.run(4); 37 | std::cout << std::endl; 38 | } 39 | -------------------------------------------------------------------------------- /test/signal.cc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace mp::placeholders; 12 | 13 | bool signal_handler(int* count, mp::wavy::loop* lo) 14 | { 15 | std::cout << "signal" << std::endl; 16 | 17 | if(++(*count) >= 3) { 18 | lo->end(); 19 | return false; 20 | } 21 | 22 | return true; 23 | } 24 | 25 | int main(void) 26 | { 27 | mp::wavy::loop lo; 28 | 29 | int count = 0; 30 | 31 | // add signal handler before starting any other threads. 32 | lo.add_signal(SIGUSR1, mp::bind( 33 | &signal_handler, &count, &lo)); 34 | 35 | lo.start(3); 36 | 37 | pid_t pid = getpid(); 38 | 39 | usleep(50*1e3); 40 | kill(pid, SIGUSR1); 41 | usleep(50*1e3); 42 | kill(pid, SIGUSR1); 43 | usleep(50*1e3); 44 | kill(pid, SIGUSR1); 45 | 46 | lo.join(); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /test/sync.cc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | struct test { 8 | test(int num1, int num2) : 9 | num1(num1), num2(num2) { } 10 | 11 | volatile int num1; 12 | volatile int num2; 13 | }; 14 | 15 | void thread_main(mp::sync* obj) 16 | { 17 | for(int i=0; i < 20; ++i) { 18 | mp::sync::ref ref(*obj); 19 | ref->num1++; 20 | ref->num1--; 21 | std::cout << (ref->num1 + ref->num2); 22 | } 23 | } 24 | 25 | int main(void) 26 | { 27 | mp::sync obj(0, 0); 28 | 29 | std::vector threads(4); 30 | for(int i=0; i < 4; ++i) { 31 | threads[i].run(mp::bind(&thread_main, &obj)); 32 | } 33 | 34 | for(int i=0; i < 4; ++i) { 35 | threads[i].join(); 36 | } 37 | 38 | std::cout << std::endl; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /test/timer.cc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace mp::placeholders; 11 | 12 | bool timer_handler(int* count, mp::wavy::loop* lo) 13 | { 14 | std::cout << "timer" << std::endl; 15 | 16 | if(++(*count) >= 3) { 17 | lo->end(); 18 | return false; 19 | } 20 | 21 | return true; 22 | } 23 | 24 | int main(void) 25 | { 26 | mp::wavy::loop lo; 27 | 28 | int count = 0; 29 | lo.add_timer(0.1, 0.1, mp::bind( 30 | &timer_handler, &count, &lo)); 31 | 32 | lo.run(4); 33 | } 34 | 35 | --------------------------------------------------------------------------------