Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

import

  • Loading branch information...
commit 6c7fc3841890bd135aa40fea8243a4d8e522c92e 0 parents
FURUHASHI Sadayuki authored
Showing with 6,122 additions and 0 deletions.
  1. +1 −0  AUTHORS
  2. +11 −0 Makefile.am
  3. +4 −0 NOTICE
  4. +47 −0 README.md
  5. +121 −0 bootstrap
  6. +84 −0 configure.in
  7. +41 −0 mp/Makefile.am
  8. +70 −0 mp/endian.h
  9. +59 −0 mp/exception.h
  10. +63 −0 mp/functional.h
  11. +99 −0 mp/iocntl.h
  12. +71 −0 mp/memory.h
  13. +82 −0 mp/object_callback.hmpl
  14. +41 −0 mp/object_delete.h
  15. +442 −0 mp/pthread.h
  16. +228 −0 mp/shared_buffer.h
  17. +133 −0 mp/signal.h
  18. +222 −0 mp/sparse_array.hmpl
  19. +280 −0 mp/stream_buffer.h
  20. +126 −0 mp/sync.hmpl
  21. +182 −0 mp/tls_set.h
  22. +40 −0 mp/utilize.h
  23. +412 −0 mp/wavy.hmpl
  24. +65 −0 mpl.rb
  25. +187 −0 mplex
  26. +22 −0 mpsrc/Makefile.am
  27. +12 −0 mpsrc/pp.h
  28. +214 −0 mpsrc/wavy_connect.cc
  29. +92 −0 mpsrc/wavy_kernel.h
  30. +302 −0 mpsrc/wavy_kernel_epoll.h
  31. +357 −0 mpsrc/wavy_kernel_kqueue.h
  32. +116 −0 mpsrc/wavy_listen.cc
  33. +466 −0 mpsrc/wavy_loop.cc
  34. +166 −0 mpsrc/wavy_loop.h
  35. +592 −0 mpsrc/wavy_out.cc
  36. +90 −0 mpsrc/wavy_out.h
  37. +45 −0 mpsrc/wavy_signal.cc
  38. +85 −0 mpsrc/wavy_signal.h
  39. +76 −0 mpsrc/wavy_timer.cc
  40. +86 −0 mpsrc/wavy_timer.h
  41. +30 −0 test/Makefile.am
  42. +78 −0 test/handler.cc
  43. +72 −0 test/listen_connect.cc
  44. +40 −0 test/signal.cc
  45. +38 −0 test/sync.cc
  46. +32 −0 test/timer.cc
1  AUTHORS
@@ -0,0 +1 @@
+FURUHASHI Sadayuki <frsyuki _at_ users.sourceforge.jp>
11 Makefile.am
@@ -0,0 +1,11 @@
+SUBDIRS = mp mpsrc test
+
+MPLEX = $(RUBY) $(PWD)/mplex -r$(PWD)/mpl.rb
+export MPLEX
+
+prep: mpl.rb
+ cd mp && $(MAKE) prep
+
+prepc:
+ cd mp && $(MAKE) prepc
+
4 NOTICE
@@ -0,0 +1,4 @@
+mpio is developed by FURUHASHI Sadayuki, licensed under Apache License,
+Version 2.0. The original software and related information is available at
+http://github.com/frsyuki/mpio
+
47 README.md
@@ -0,0 +1,47 @@
+mpio
+====
+Multipurpose concurrent I/O framework for C++
+
+## Overview
+
+
+## Libraries
+
+### Wavy
+Wavy is a multithreaded event-driven I/O library.
+
+### sync
+
+### utilize
+
+### shared_buffer
+
+### stream_buffer
+
+### sparse_array
+
+### pthread
+
+### signal
+
+### functional
+
+### memory
+
+
+## License
+
+ Copyright (C) 2008-2010 FURUHASHI Sadayuki
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
121 bootstrap
@@ -0,0 +1,121 @@
+#!/bin/sh
+# vim:ts=4:sw=4
+# Calls autotools to build configure script and Makefile.in.
+# Generated automatically using bootstrapper 0.2.1
+# http://bootstrapper.sourceforge.net/
+#
+# Copyright (C) 2002 Anthony Ventimiglia
+#
+# This bootstrap script is free software; you can redistribute
+# it and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+#
+# Calls proper programs to create configure script and Makefile.in files.
+# if run with the --clean option, bootstrap removes files it generates. To
+# clean all autogenerated files (eg: for cvs imports) first run
+# make distclean, then bootstrap --clean
+# see bootstrapper(1) for more infor
+
+
+if test x"$1" = x"--help"; then
+ echo "$0: automatic bootstrapping utility for GNU Autotools"
+ echo " cleans up old autogenerated files and runs autoconf,"
+ echo " automake and aclocal on local directory"
+ echo
+ echo " --clean clean up auto-generated files without"
+ echo " creating new scripts"
+ echo
+ exit 0
+fi
+
+
+mkdir -p ac
+test -f AUTHORS || touch AUTHORS
+test -f COPYING || touch COPYING
+test -f ChangeLog || touch ChangeLog
+test -f NEWS || touch NEWS
+test -f README || touch README
+
+
+ACLOCAL="aclocal"
+ACLOCAL_FILES="aclocal.m4"
+ALWAYS_CLEAN="config.status config.log config.cache libtool"
+AUTOCONF="autoconf"
+AUTOCONF_FILES="configure"
+AUTOHEADER="autoheader"
+AUTOHEADER_FILES=""
+AUTOMAKE="automake --add-missing --copy"
+AUTOMAKE_FILES="config.sub stamp-h.in ltmain.sh missing mkinstalldirs install-sh config.guess"
+CONFIG_AUX_DIR="."
+CONFIG_FILES="stamp-h ltconfig"
+CONFIG_HEADER=""
+if [ x`uname` = x"Darwin" ]; then
+ LIBTOOLIZE="glibtoolize --force --copy"
+else
+ LIBTOOLIZE="libtoolize --force --copy"
+fi
+LIBTOOLIZE_FILES="config.sub ltmain.sh config.guess"
+RM="rm"
+SUBDIRS="[]"
+
+
+# These are files created by configure, so we'll always clean them
+for i in $ALWAYS_CLEAN; do
+ test -f $i && \
+ $RM $i
+done
+
+if test x"$1" = x"--clean"; then
+ #
+ #Clean Files left by previous bootstrap run
+ #
+ if test -n "$CONFIG_AUX_DIR";
+ then CONFIG_AUX_DIR="$CONFIG_AUX_DIR/"
+ fi
+ # Clean Libtoolize generated files
+ for cf in $LIBTOOLIZE_FILES; do
+ cf="$CONFIG_AUX_DIR$cf"
+ test -f $cf && \
+ $RM $cf
+ done
+ #aclocal.m4 created by aclocal
+ test -f $ACLOCAL_FILES && $RM $ACLOCAL_FILES
+ #Clean Autoheader Generated files
+ for cf in $AUTOHEADER_FILES; do
+ cf=$CONFIG_AUX_DIR$cf
+ test -f $cf && \
+ $RM $cf
+ done
+ # remove config header (Usaually config.h)
+ test -n "$CONFIG_HEADER" && test -f $CONFIG_HEADER && $RM $CONFIG_HEADER
+ #Clean Automake generated files
+ for cf in $AUTOMAKE_FILES; do
+ cf=$CONFIG_AUX_DIR$cf
+ test -f $cf && \
+ $RM $cf
+ done
+ for i in $SUBDIRS; do
+ test -f $i/Makefile.in && \
+ $RM $i/Makefile.in
+ done
+ #Autoconf generated files
+ for cf in $AUTOCONF_FILES; do
+ test -f $cf && \
+ $RM $cf
+ done
+ for cf in $CONFIG_FILES; do
+ cf="$CONFIG_AUX_DIR$cf"
+ test -f $cf && \
+ $RM $cf
+ done
+else
+ $LIBTOOLIZE
+ $ACLOCAL
+ $AUTOHEADER
+ $AUTOMAKE
+ $AUTOCONF
+fi
+
+
84 configure.in
@@ -0,0 +1,84 @@
+AC_INIT(mpsrc/wavy_kernel.h)
+AC_CONFIG_AUX_DIR(ac)
+AC_CANONICAL_TARGET
+
+AM_INIT_AUTOMAKE(mpio, 0.1.0)
+AC_CONFIG_HEADER(config.h)
+
+AC_SUBST(CFLAGS)
+CFLAGS="-O4 -Wall $CFLAGS"
+
+AC_SUBST(CXXFLAGS)
+CXXFLAGS="-O4 -Wall $CXXFLAGS"
+
+AC_CHECK_PROG(RUBY, ruby, ruby)
+if test "x$RUBY" = x; then
+ AC_MSG_ERROR([cannot find ruby. Ruby is needed to build.])
+fi
+
+AC_PROG_CC
+AC_PROG_CXX
+
+AC_PROG_LIBTOOL
+AM_PROG_AS
+AM_PROG_CC_C_O
+
+
+AC_CACHE_CHECK([for __sync_* atomic operations], kumofs_cv_atomic_ops, [
+ AC_TRY_LINK([
+ int atomic_sub(int i) { return __sync_sub_and_fetch(&i, 1); }
+ int atomic_add(int i) { return __sync_add_and_fetch(&i, 1); }
+ int atomic_cas(int i) { return __sync_bool_compare_and_swap(&i, 0, 1); }
+ ], [], kumofs_cv_atomic_ops="yes")
+ ])
+if test "$kumofs_cv_atomic_ops" != "yes"; then
+ AC_MSG_ERROR([__sync_* atomic operations are not supported.
+
+Note that gcc < 4.1 is not supported.
+
+If you are using gcc >= 4.1 and the default target CPU architecture is "i386", try to
+add CFLAGS="--march=i686" and CXXFLAGS="-march=i686" options to ./configure as follows:
+
+ $ ./configure CFLAGS="-march=i686" CXXFLAGS="-march=i686"
+])
+fi
+
+
+AC_CHECK_LIB(stdc++, main)
+
+AC_CHECK_LIB(pthread,pthread_create,,
+ AC_MSG_ERROR([Can't find pthread library]))
+
+
+case "$target_os" in
+solaris*)
+ AC_CHECK_LIB(socket,accept,,
+ AC_MSG_ERROR([Can't find libsocket.]))
+ AC_CHECK_LIB(nsl,inet_ntop,,
+ AC_MSG_ERROR([Can't find libnsl.]))
+ AC_CHECK_LIB(sendfile,sendfile,,
+ AC_MSG_ERROR([Can't find libsendfile.]))
+ CXXFLAGS="$CXXFLAGS -D_REENTRANT"
+ CFLAGS="$CFLAGS -D_REENTRANT"
+ ;;
+esac
+
+
+AC_MSG_CHECKING([if debug option is enabled])
+AC_ARG_ENABLE(debug,
+ AS_HELP_STRING([--disable-debug],
+ [disable assert macros and omit -g option.]) )
+if test "$enable_debug" != "no"; then
+ CXXFLAGS="$CXXFLAGS -g"
+ CFLAGS="$CFLAGS -g"
+else
+ CXXFLAGS="$CXXFLAGS -DNDEBUG"
+ CFLAGS="$CFLAGS -DNDEBUG"
+fi
+AC_MSG_RESULT($enable_debug)
+
+AC_OUTPUT([Makefile
+ mp/Makefile
+ mpsrc/Makefile
+ test/Makefile])
+
41 mp/Makefile.am
@@ -0,0 +1,41 @@
+
+libmpio_includedir = $(includedir)/mp
+
+libmpio_include_HEADERS = \
+ endian.h \
+ exception.h \
+ functional.h \
+ iocntl.h \
+ memory.h \
+ object_callback.h \
+ object_delete.h \
+ pthread.h \
+ shared_buffer.h \
+ signal.h \
+ sparse_array.h \
+ stream_buffer.h \
+ sync.h \
+ tls_set.h \
+ utilize.h \
+ wavy.h
+
+PREP_SOURCE = \
+ object_callback.hmpl \
+ sparse_array.hmpl \
+ sync.hmpl \
+ wavy.hmpl
+
+PREP_TARGET = $(PREP_SOURCE:mpl=)
+EXTRA_DIST = $(PREP_SOURCE)
+
+%.h: %.hmpl
+ $(MPLEX) $< -o $@
+
+%.cc: %.ccmpl
+ $(MPLEX) $< -o $@
+
+prep: $(PREP_TARGET)
+
+prepc:
+ rm -f $(PREP_TARGET)
+
70 mp/endian.h
@@ -0,0 +1,70 @@
+//
+// mpio endian
+//
+// Copyright (C) 2009-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_ENDIAN_H__
+#define MP_ENDIAN_H__
+#ifdef MP_EXPERIMENTAL
+
+#include <arpa/inet.h>
+
+namespace mp {
+
+
+#if 0
+inline uint16_t htons(uint16_t x) { ::htons(x); }
+inline uint16_t ntohs(uint16_t x) { ::ntohs(x); }
+inline uint32_t htonl(uint32_t x) { ::htonl(x); }
+inline uint32_t ntohl(uint32_t x) { ::ntohl(x); }
+#endif
+
+
+#if defined(__BIG_ENDIAN__) || (!defined(__LITTLE_ENDIAN__) && __BYTE_ORDER == __BIG_ENDIAN)
+inline uint64_t htonll(uint64_t x) { return x; }
+inline uint64_t ntohll(uint64_t x) { return x; }
+#else
+
+#if defined(bswap_64)
+inline uint64_t htonll(uint64_t x) { return bswap_64(x); }
+inline uint64_t ntohll(uint64_t x) { return bswap_64(x); }
+#elif defined(__DARWIN_OSSwapInt64)
+inline uint64_t htonll(uint64_t x) { return __DARWIN_OSSwapInt64(x); }
+inline uint64_t ntohll(uint64_t x) { return __DARWIN_OSSwapInt64(x); }
+#elif defined(_byteswap_uint64)
+inline uint64_t htonll(uint64_t x) { return _byteswap_uint64(x); }
+inline uint64_t ntohll(uint64_t x) { return _byteswap_uint64(x); }
+#else
+inline uint64_t htonll(uint64_t x) {
+ return ((x << 56) & 0xff00000000000000ULL ) |
+ ((x << 40) & 0x00ff000000000000ULL ) |
+ ((x << 24) & 0x0000ff0000000000ULL ) |
+ ((x << 8) & 0x000000ff00000000ULL ) |
+ ((x >> 8) & 0x00000000ff000000ULL ) |
+ ((x >> 24) & 0x0000000000ff0000ULL ) |
+ ((x >> 40) & 0x000000000000ff00ULL ) |
+ ((x >> 56) & 0x00000000000000ffULL ) ;
+}
+inline uint64_t ntohll(uint64_t x) { return htonll(x); }
+#endif
+
+#endif
+
+
+} // namespace mp
+
+#endif /* MP_EXPERIMENTAL */
+#endif /* mp/endian.h */
+
59 mp/exception.h
@@ -0,0 +1,59 @@
+//
+// mpio exception
+//
+// Copyright (C) 2008-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_EXCEPTION_H__
+#define MP_EXCEPTION_H__
+
+#include <stdexcept>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+namespace mp {
+
+
+struct system_error : std::runtime_error {
+ static std::string errno_string(int err)
+ {
+ char buf[512];
+#if defined(__linux__)
+ char *ret;
+ ret = strerror_r(err, buf, sizeof(buf)-1);
+ return std::string(ret);
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined(__SunOS__)
+ strerror_r(err, buf, sizeof(buf)-1);
+ return std::string(buf);
+#else
+ return std::string(strerror(err));
+#endif
+ }
+
+ system_error(int err, const std::string& msg) :
+ std::runtime_error(msg + ": " + errno_string(err)) {}
+};
+
+
+struct event_error : system_error {
+ event_error(int err, const std::string& msg) :
+ system_error(errno, msg) {}
+};
+
+
+} // namespace mp
+
+#endif /* mp/exception.h */
+
63 mp/functional.h
@@ -0,0 +1,63 @@
+//
+// mp::functional
+//
+// Copyright (C) 2008-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_FUNCTIONAL_H__
+#define MP_FUNCTIONAL_H__
+
+#ifdef MP_FUNCTIONAL_BOOST
+#include <boost/tr1/functional.hpp>
+namespace mp {
+ using std::tr1::function;
+ using std::tr1::bind;
+ namespace placeholders {
+ using namespace std::tr1::placeholders;
+ }
+}
+#else
+#ifdef MP_FUNCTIONAL_BOOST_ORG
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+namespace mp {
+ using boost::function;
+ using boost::bind;
+ namespace placeholders { }
+}
+#else
+#ifndef MP_FUNCTIONAL_STANDARD
+#include <tr1/functional>
+namespace mp {
+ using std::tr1::function;
+ using std::tr1::bind;
+ namespace placeholders {
+ using namespace std::tr1::placeholders;
+ }
+}
+#else
+#include <functional>
+namespace mp {
+ using std::function;
+ using std::bind;
+ namespace placeholders {
+ using namespace std::placeholders;
+ }
+}
+#endif
+#endif
+#endif
+
+#endif /* mp/functional.h */
+
99 mp/iocntl.h
@@ -0,0 +1,99 @@
+//
+// mpio iocntl
+//
+// Copyright (C) 2008-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_IOCNTL_H__
+#define MP_IOCNTL_H__
+#ifdef MP_EXPERIMENTAL
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <memory>
+
+namespace mp {
+
+
+inline bool set_nonblock(int fd)
+{
+ return ::fcntl(fd, F_SETFL, O_NONBLOCK) >= 0;
+}
+
+inline bool set_tcp_nodelay(int fd)
+{
+ int on = 1;
+ return ::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) >= 0;
+}
+
+inline bool set_linger(int fd, bool sync, bool wait)
+{
+ struct linger opt = {(sync ? 1 : 0), (wait ? 1 : 0)};
+ return ::setsockopt(fd, SOL_SOCKET, SO_LINGER, (void *)&opt, sizeof(opt)) >= 0;
+}
+
+inline bool set_reuse_addr(int fd)
+{
+ int on = 1;
+ return ::setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) >= 0;
+}
+
+inline bool set_recv_timeout(int fd, struct timeval tv)
+{
+ return ::setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) >= 0;
+}
+
+inline bool set_send_timeout(int fd, struct timeval tv)
+{
+ return ::setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) >= 0;
+}
+
+inline bool set_recv_timeout(int fd, double sec)
+{
+ if(sec <= 0) { return true; }
+ struct timeval tv = {sec, sec*1e6};
+ return set_recv_timeout(tv);
+}
+
+inline bool set_send_timeout(int fd, double sec)
+{
+ if(sec <= 0) { return true; }
+ struct timeval tv = {sec, sec*1e6};
+ return set_send_timeout(tv);
+}
+
+inline bool isEAGAIN(int err = errno)
+{
+ return err == EAGAIN;
+}
+
+inline bool isEINTR(int err = errno)
+{
+ return err == EINVAL;
+}
+
+// #define isEAGAIN mp::isEAGAIN()
+// #define isEINTR mp::isEINTR()
+
+
+} // namespace mp
+
+#endif /* MP_EXPERIMENTAL */
+#endif /* mp/iocntl.h */
+
71 mp/memory.h
@@ -0,0 +1,71 @@
+//
+// mpio memory
+//
+// Copyright (C) 2008-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_MEMORY_H__
+#define MP_MEMORY_H__
+
+#ifdef MP_MEMORY_BOOST
+#include <boost/tr1/memory>
+namespace mp {
+ using std::tr1::shared_ptr;
+ using std::tr1::wak_ptr;
+ //using std::tr2::scoped_ptr;
+ using std::tr1::static_pointer_cast;
+ using std::tr1::dynamic_pointer_cast;
+ using std::tr1::enable_shared_from_this;
+}
+#else
+#ifdef MP_MEMORY_BOOST_ORG
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+//#include <boost/scoped_ptr.hpp>
+namespace mp {
+ using boost::shared_ptr;
+ using boost::weak_ptr;
+ //using boost::scoped_ptr;
+ using boost::static_pointer_cast;
+ using boost::dynamic_pointer_cast;
+ using boost::enable_shared_from_this;
+}
+#else
+#ifndef MP_MEMORY_STANDARD
+#include <tr1/memory>
+namespace mp {
+ using std::tr1::shared_ptr;
+ using std::tr1::weak_ptr;
+ //using std::tr2::scoped_ptr;
+ using std::tr1::static_pointer_cast;
+ using std::tr1::dynamic_pointer_cast;
+ using std::tr1::enable_shared_from_this;
+}
+#else
+#include <memory>
+namespace mp {
+ using std::shared_ptr;
+ using std::weak_ptr;
+ //using std::scoped_ptr;
+ using std::static_pointer_cast;
+ using std::dynamic_pointer_cast;
+ using std::enable_shared_from_this;
+}
+#endif
+#endif
+#endif
+
+#endif /* mp/memory.h */
+
82 mp/object_callback.hmpl
@@ -0,0 +1,82 @@
+//
+// mpio object_callback
+//
+// Copyright (C) 2008-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_OBJECT_CALLBACK_H__
+#define MP_OBJECT_CALLBACK_H__
+
+#include "mp/memory.h"
+#include "mp/object_delete.h"
+
+namespace mp {
+
+
+template <typename Signature>
+struct object_callback;
+
+template <typename R>
+struct object_callback<R ()>
+{
+ template <typename T, R (T::*MemFun)()>
+ static R mem_fun(void* obj)
+ {
+ return (reinterpret_cast<T*>(obj)->*MemFun)();
+ }
+
+ template <typename T, R (T::*MemFun)()>
+ static R const_mem_fun(const void* obj)
+ {
+ return (reinterpret_cast<const T*>(obj)->*MemFun)();
+ }
+
+ template <typename T, R (T::*MemFun)()>
+ static R shared_fun(shared_ptr<T> obj)
+ {
+ return (obj.get()->*MemFun)();
+ }
+};
+
+%varlen_each do |gen|
+template <typename R, [%gen.template%]>
+struct object_callback<R ([%gen.args%])>
+{
+ template <typename T, R (T::*MemFun)([%gen.args%])>
+ static R mem_fun(void* obj, [%gen.args%])
+ {
+ return (reinterpret_cast<T*>(obj)->*MemFun)([%gen.params%]);
+ }
+
+ template <typename T, R (T::*MemFun)([%gen.args%])>
+ static R const_mem_fun(const void* obj, [%gen.args%])
+ {
+ return (reinterpret_cast<const T*>(obj)->*MemFun)([%gen.params%]);
+ }
+
+ template <typename T, R (T::*MemFun)([%gen.args%])>
+ static R shared_fun(shared_ptr<T> obj, [%gen.args%])
+ {
+ return (obj.get()->*MemFun)([%gen.params%]);
+ }
+};
+
+%end
+
+
+} // namespace mp
+
+#endif /* mp/object_callback.h */
+
+%# vim: filetype=mplex
41 mp/object_delete.h
@@ -0,0 +1,41 @@
+//
+// mpio object_delete
+//
+// Copyright (C) 2008-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_OBJECT_DELETE_H__
+#define MP_OBJECT_DELETE_H__
+
+namespace mp {
+
+
+template <typename T>
+static void object_delete(void* obj)
+{
+ delete reinterpret_cast<T*>(obj);
+}
+
+
+template <typename T>
+static void object_destructor(void* obj)
+{
+ reinterpret_cast<T*>(obj)->~T();
+}
+
+
+} // namespace mp
+
+#endif /* mp/object_delete.h */
+
442 mp/pthread.h
@@ -0,0 +1,442 @@
+//
+// mpio pthread
+//
+// Copyright (C) 2008-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_PTHREAD_H__
+#define MP_PTHREAD_H__
+
+#include "mp/exception.h"
+#include "mp/functional.h"
+#include <pthread.h>
+
+namespace mp {
+
+
+struct pthread_error : system_error {
+ pthread_error(int errno_, const std::string& msg) :
+ system_error(errno_, msg) {}
+};
+
+
+struct pthread_thread {
+private:
+ typedef function<void ()> function_t;
+
+public:
+ void create(void* (*func)(void*), void* user)
+ {
+ int err = pthread_create(&m_thread, NULL,
+ func, user);
+ if(err) { throw pthread_error(err, "failed to create thread"); }
+ }
+
+ void run(function_t func)
+ {
+ std::auto_ptr<function_t> f(new function_t(func));
+ create(&trampoline, reinterpret_cast<void*>(f.get()));
+ f.release();
+ }
+
+ void detach()
+ {
+ int err = pthread_detach(m_thread);
+ if(err) { throw pthread_error(err, "failed to detach thread"); }
+ }
+
+ void* join()
+ {
+ void* ret;
+ int err = pthread_join(m_thread, &ret);
+ if(err) { throw pthread_error(err, "failed to join thread"); }
+ return ret;
+ }
+
+ void cancel()
+ {
+ pthread_cancel(m_thread);
+ }
+
+
+ bool operator== (const pthread_thread& other) const
+ {
+ return pthread_equal(m_thread, other.m_thread);
+ }
+
+ bool operator!= (const pthread_thread& other) const
+ {
+ return !(*this == other);
+ }
+
+
+ static void exit(void* retval = NULL)
+ {
+ pthread_exit(retval);
+ }
+
+private:
+ pthread_t m_thread;
+
+ static void* trampoline(void* user);
+};
+
+
+template <typename IMPL>
+struct pthread_thread_impl : public pthread_thread {
+ pthread_thread_impl() : pthread_thread(this) { }
+ virtual ~pthread_thread_impl() { }
+};
+
+
+class pthread_mutex {
+public:
+ pthread_mutex(const pthread_mutexattr_t *attr = NULL)
+ {
+ pthread_mutex_init(&m_mutex, attr);
+ }
+
+ pthread_mutex(int kind)
+ {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, kind);
+ pthread_mutex_init(&m_mutex, &attr);
+ }
+
+ ~pthread_mutex()
+ {
+ pthread_mutex_destroy(&m_mutex);
+ }
+
+public:
+ void lock()
+ {
+ int err = pthread_mutex_lock(&m_mutex);
+ if(err != 0) { throw pthread_error(-err, "failed to lock pthread mutex"); }
+ }
+
+ bool trylock()
+ {
+ int err = pthread_mutex_trylock(&m_mutex);
+ if(err != 0) {
+ if(err == EBUSY) { return false; }
+ throw pthread_error(-err, "failed to trylock pthread mutex");
+ }
+ return true;
+ }
+
+ void unlock()
+ {
+ int err = pthread_mutex_unlock(&m_mutex);
+ if(err != 0) { throw pthread_error(-err, "failed to unlock pthread mutex"); }
+ }
+
+public:
+ pthread_mutex_t* get() { return &m_mutex; }
+private:
+ pthread_mutex_t m_mutex;
+private:
+ pthread_mutex(const pthread_mutex&);
+};
+
+
+class pthread_rwlock {
+public:
+ pthread_rwlock(const pthread_rwlockattr_t *attr = NULL)
+ {
+ pthread_rwlock_init(&m_mutex, attr);
+ }
+
+ // FIXME kind
+ //pthread_rwlock(int kind)
+ //{
+ // pthread_rwlockattr_t attr;
+ // pthread_rwlockattr_init(&attr);
+ // pthread_rwlockattr_settype(&attr, kind);
+ // pthread_rwlock_init(&m_mutex, &attr);
+ //}
+
+ ~pthread_rwlock()
+ {
+ pthread_rwlock_destroy(&m_mutex);
+ }
+
+public:
+ void rdlock()
+ {
+ int err = pthread_rwlock_rdlock(&m_mutex);
+ if(err != 0) { throw pthread_error(-err, "failed to read lock pthread rwlock"); }
+ }
+
+ bool tryrdlock()
+ {
+ int err = pthread_rwlock_tryrdlock(&m_mutex);
+ if(err != 0) {
+ if(err == EBUSY) { return false; }
+ throw pthread_error(-err, "failed to read trylock pthread rwlock");
+ }
+ return true;
+ }
+
+ void wrlock()
+ {
+ int err = pthread_rwlock_wrlock(&m_mutex);
+ if(err != 0) { throw pthread_error(-err, "failed to write lock pthread rwlock"); }
+ }
+
+ bool trywrlock()
+ {
+ int err = pthread_rwlock_trywrlock(&m_mutex);
+ if(err != 0) {
+ if(err == EBUSY) { return false; }
+ throw pthread_error(-err, "failed to write trylock pthread rwlock");
+ }
+ return true;
+ }
+
+ void unlock()
+ {
+ int err = pthread_rwlock_unlock(&m_mutex);
+ if(err != 0) { throw pthread_error(-err, "failed to unlock pthread rwlock"); }
+ }
+
+public:
+ pthread_rwlock_t* get() { return &m_mutex; }
+private:
+ pthread_rwlock_t m_mutex;
+private:
+ pthread_rwlock(const pthread_rwlock&);
+};
+
+
+class pthread_scoped_lock {
+public:
+ pthread_scoped_lock() : m_mutex(NULL) { }
+
+ pthread_scoped_lock(pthread_mutex& mutex) : m_mutex(NULL)
+ {
+ mutex.lock();
+ m_mutex = &mutex;
+ }
+
+ ~pthread_scoped_lock()
+ {
+ if(m_mutex) {
+ m_mutex->unlock();
+ }
+ }
+
+public:
+ void unlock()
+ {
+ if(m_mutex) {
+ m_mutex->unlock();
+ m_mutex = NULL;
+ }
+ }
+
+ void relock(pthread_mutex& mutex)
+ {
+ unlock();
+ mutex.lock();
+ m_mutex = &mutex;
+ }
+
+private:
+ pthread_mutex* m_mutex;
+private:
+ pthread_scoped_lock(const pthread_scoped_lock&);
+};
+
+
+class pthread_scoped_rdlock {
+public:
+ pthread_scoped_rdlock() : m_mutex(NULL) { }
+
+ pthread_scoped_rdlock(pthread_rwlock& mutex) : m_mutex(NULL)
+ {
+ mutex.rdlock();
+ m_mutex = &mutex;
+ }
+
+ ~pthread_scoped_rdlock()
+ {
+ if(m_mutex) {
+ m_mutex->unlock();
+ }
+ }
+
+public:
+ void unlock()
+ {
+ if(m_mutex) {
+ m_mutex->unlock();
+ m_mutex = NULL;
+ }
+ }
+
+ void relock(pthread_rwlock& mutex)
+ {
+ unlock();
+ mutex.rdlock();
+ m_mutex = &mutex;
+ }
+
+private:
+ pthread_rwlock* m_mutex;
+private:
+ pthread_scoped_rdlock(const pthread_scoped_rdlock&);
+};
+
+
+class pthread_scoped_wrlock {
+public:
+ pthread_scoped_wrlock() : m_mutex(NULL) { }
+
+ pthread_scoped_wrlock(pthread_rwlock& mutex) : m_mutex(NULL)
+ {
+ mutex.wrlock();
+ m_mutex = &mutex;
+ }
+
+ ~pthread_scoped_wrlock()
+ {
+ if(m_mutex) {
+ m_mutex->unlock();
+ }
+ }
+
+public:
+ void unlock()
+ {
+ if(m_mutex) {
+ m_mutex->unlock();
+ m_mutex = NULL;
+ }
+ }
+
+ void relock(pthread_rwlock& mutex)
+ {
+ unlock();
+ mutex.wrlock();
+ m_mutex = &mutex;
+ }
+
+private:
+ pthread_rwlock* m_mutex;
+private:
+ pthread_scoped_wrlock(const pthread_scoped_wrlock&);
+};
+
+
+class pthread_cond {
+public:
+ pthread_cond(const pthread_condattr_t *attr = NULL)
+ {
+ pthread_cond_init(&m_cond, attr);
+ }
+
+ ~pthread_cond()
+ {
+ pthread_cond_destroy(&m_cond);
+ }
+
+public:
+ void signal()
+ {
+ int err = pthread_cond_signal(&m_cond);
+ if(err != 0) { throw pthread_error(-err, "failed to signal pthread cond"); }
+ }
+
+ void broadcast()
+ {
+ int err = pthread_cond_broadcast(&m_cond);
+ if(err != 0) { throw pthread_error(-err, "failed to broadcast pthread cond"); }
+ }
+
+ void wait(pthread_mutex& mutex)
+ {
+ int err = pthread_cond_wait(&m_cond, mutex.get());
+ if(err != 0) { throw pthread_error(-err, "failed to wait pthread cond"); }
+ }
+
+ bool timedwait(pthread_mutex& mutex, const struct timespec *abstime)
+ {
+ int err = pthread_cond_timedwait(&m_cond, mutex.get(), abstime);
+ if(err != 0) {
+ if(err == ETIMEDOUT) { return false; }
+ throw pthread_error(-err, "failed to timedwait pthread cond");
+ }
+ return true;
+ }
+
+public:
+ pthread_cond_t* get() { return &m_cond; }
+private:
+ pthread_cond_t m_cond;
+private:
+ pthread_cond(const pthread_cond&);
+};
+
+
+} // namespace mp
+
+
+#include <iostream>
+#include <typeinfo>
+#ifndef MP_NO_CXX_ABI_H
+#include <cxxabi.h>
+#endif
+
+namespace mp {
+
+
+inline void* pthread_thread::trampoline(void* user)
+try {
+ std::auto_ptr<function_t> f(reinterpret_cast<function_t*>(user));
+ (*f)();
+ return NULL;
+
+} catch (std::exception& e) {
+ try {
+#ifndef MP_NO_CXX_ABI_H
+ int status;
+ std::cerr
+ << "thread terminated with throwing an instance of '"
+ << abi::__cxa_demangle(typeid(e).name(), 0, 0, &status)
+ << "'\n"
+ << " what(): " << e.what() << std::endl;
+
+ std::cerr
+ << "thread terminated with throwing an instance of '"
+ << typeid(e).name()
+ << "'\n"
+ << " what(): " << e.what() << std::endl;
+#endif
+ } catch (...) {}
+ throw;
+
+} catch (...) {
+ try {
+ std::cerr << "thread terminated with throwing an unknown object" << std::endl;
+ } catch (...) {}
+ throw;
+}
+
+
+} // namespace mp
+
+#endif /* mp/pthread.h */
+
228 mp/shared_buffer.h
@@ -0,0 +1,228 @@
+//
+// mpio shared_buffer
+//
+// Copyright (C) 2009-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_SHARED_BUFFER_H__
+#define MP_SHARED_BUFFER_H__
+
+#include <memory>
+#include <stdlib.h>
+
+#ifndef MP_SHARED_BUFFER_INITIAL_BUFFER_SIZE
+#define MP_SHARED_BUFFER_INITIAL_BUFFER_SIZE 8*1024
+#endif
+
+namespace mp {
+
+
+class shared_buffer {
+public:
+ shared_buffer(size_t init_size = MP_SHARED_BUFFER_INITIAL_BUFFER_SIZE);
+ ~shared_buffer();
+
+public:
+ class ref {
+ public:
+ ref();
+ ref(void* p);
+ ref(const ref& o);
+ ~ref();
+ void clear();
+ void reset(void* p);
+ void swap(ref& x);
+ private:
+ void* m;
+ };
+
+ void reserve_buffer(size_t len,
+ size_t init_size = MP_SHARED_BUFFER_INITIAL_BUFFER_SIZE);
+
+ void* buffer();
+ size_t buffer_capacity() const;
+
+ ref hold_buffer(size_t size,
+ size_t init_size = MP_SHARED_BUFFER_INITIAL_BUFFER_SIZE);
+
+private:
+ char* m_buffer;
+ size_t m_used;
+ size_t m_free;
+
+private:
+ void expand_buffer(size_t len, size_t init_size);
+
+ typedef volatile unsigned int count_t;
+ static void init_count(void* d);
+ static void decr_count(void* d);
+ static void incr_count(void* d);
+ static count_t get_count(void* d);
+
+private:
+ shared_buffer(const shared_buffer&);
+};
+
+
+
+inline void shared_buffer::init_count(void* d)
+{
+ *(volatile count_t*)d = 1;
+}
+
+inline void shared_buffer::decr_count(void* d)
+{
+ //if(--*(count_t*)d == 0) {
+ if(__sync_sub_and_fetch((count_t*)d, 1) == 0) {
+ ::free(d);
+ }
+}
+
+inline void shared_buffer::incr_count(void* d)
+{
+ //++*(count_t*)d;
+ __sync_add_and_fetch((count_t*)d, 1);
+}
+
+inline shared_buffer::count_t shared_buffer::get_count(void* d)
+{
+ return *(count_t*)d;
+}
+
+
+inline shared_buffer::ref::ref() : m(NULL) { }
+
+inline shared_buffer::ref::ref(void* p) :
+ m(p)
+{
+ incr_count(m);
+}
+
+inline shared_buffer::ref::ref(const ref& o) :
+ m(o.m)
+{
+ incr_count(m);
+}
+
+inline void shared_buffer::ref::clear()
+{
+ if(m) {
+ decr_count(m);
+ m = NULL;
+ }
+}
+
+inline shared_buffer::ref::~ref()
+{
+ clear();
+}
+
+inline void shared_buffer::ref::reset(void* p)
+{
+ clear();
+ m = p;
+ incr_count(m);
+}
+
+inline void shared_buffer::ref::swap(ref& x)
+{
+ void* tmp = m;
+ m = x.m;
+ x.m = tmp;
+}
+
+
+inline shared_buffer::shared_buffer(size_t init_size)
+{
+ const size_t initsz = std::max(init_size, sizeof(count_t));
+ m_buffer = (char*)::malloc(initsz);
+ if(m_buffer == NULL) { throw std::bad_alloc(); }
+
+ init_count(m_buffer);
+ m_used = sizeof(count_t);
+ m_free = initsz - m_used;
+}
+
+inline shared_buffer::~shared_buffer()
+{
+ decr_count(m_buffer);
+}
+
+inline void* shared_buffer::buffer()
+{
+ return m_buffer + m_used;
+}
+
+inline size_t shared_buffer::buffer_capacity() const
+{
+ return m_free;
+}
+
+inline void shared_buffer::reserve(size_t len, size_t init_size)
+{
+ if(get_count(m_buffer) == 1) {
+ // rewind buffer
+ m_free += m_used - sizeof(count_t);
+ m_used = sizeof(count_t);
+ }
+ if(m_free < len) {
+ expand_buffer(len, init_size);
+ }
+}
+
+inline ref shared_buffer::hold_buffer(
+ size_t len, size_t init_size)
+{
+ reserve(len, init_size);
+ char* tmp = m_buffer + m_used;
+ m_used += len;
+ m_free -= len;
+ return result_ref(m_buffer);
+}
+
+inline void shared_buffer::expand_buffer(size_t len, size_t init_size)
+{
+ if(m_used == sizeof(count_t)) {
+ size_t next_size = (m_used + m_free) * 2;
+ while(next_size < len + m_used) { next_size *= 2; }
+
+ char* tmp = (char*)::realloc(m_buffer, next_size);
+ if(!tmp) { throw std::bad_alloc(); }
+
+ m_buffer = tmp;
+ m_free = next_size - m_used;
+
+ } else {
+ const size_t initsz = std::max(init_size, sizeof(count_t));
+
+ size_t next_size = initsz; // include sizeof(count_t)
+ while(next_size < len + sizeof(count_t)) { next_size *= 2; }
+
+ char* tmp = (char*)::malloc(next_size);
+ if(!tmp) { throw std::bad_alloc(); }
+ init_count(tmp);
+
+ decr_count(m_buffer);
+
+ m_buffer = tmp;
+ m_used = sizeof(count_t);
+ m_free = next_size - m_used;
+ }
+}
+
+
+} // namespace mp
+
+#endif /* mp/shared_buffer.h */
+
133 mp/signal.h
@@ -0,0 +1,133 @@
+//
+// mpio signal
+//
+// Copyright (C) 2008-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_SIGNAL_H__
+#define MP_SIGNAL_H__
+
+#include "mp/exception.h"
+#include "mp/pthread.h"
+#include <signal.h>
+
+namespace mp {
+
+
+class sigset {
+public:
+ sigset(const sigset_t& set) :
+ m_set(set) { }
+
+ sigset()
+ { set_empty(); }
+
+ sigset& add(int signo)
+ { sigaddset(&m_set, signo); return* this; }
+
+ sigset& del(int signo)
+ { sigdelset(&m_set, signo); return* this; }
+
+ sigset& set_empty()
+ { sigemptyset(&m_set); return* this; }
+
+ sigset& set_fill()
+ { sigfillset(&m_set); return* this; }
+
+ sigset_t* get()
+ {
+ return &m_set;
+ }
+
+ const sigset_t* get() const
+ {
+ return &m_set;
+ }
+
+private:
+ sigset_t m_set;
+};
+
+
+class scoped_sigprocmask {
+public:
+ scoped_sigprocmask(const sigset& set) : m_set(set)
+ {
+ if(sigprocmask(SIG_BLOCK, m_set.get(), NULL) < 0) {
+ throw system_error(errno, "failed to set sigprocmask");
+ }
+ }
+
+ scoped_sigprocmask(const sigset_t& set) : m_set(set)
+ {
+ if(sigprocmask(SIG_BLOCK, m_set.get(), NULL) < 0) {
+ throw system_error(errno, "failed to set sigprocmask");
+ }
+ }
+
+ ~scoped_sigprocmask()
+ {
+ sigprocmask(SIG_UNBLOCK, m_set.get(), NULL);
+ }
+
+ const sigset& get_sigset() const { return m_set; }
+
+private:
+ sigset m_set;
+
+private:
+ scoped_sigprocmask();
+ scoped_sigprocmask(const scoped_sigprocmask&);
+};
+
+
+class pthread_signal : public pthread_thread {
+public:
+ typedef function<bool (int signo)> handler_t;
+
+ pthread_signal(const sigset& set, handler_t handler) :
+ m_mask(set)
+ {
+ run(mp::bind(&pthread_signal::thread_main, set, handler));
+ }
+
+ ~pthread_signal() { }
+
+public:
+ static void thread_main(sigset set, handler_t handler)
+ {
+ int signo;
+ while(true) {
+ if(sigwait(set.get(), &signo) != 0) {
+ signo = -1;
+ }
+ if(!handler(signo)) {
+ return;
+ }
+ }
+ }
+
+private:
+ scoped_sigprocmask m_mask;
+
+private:
+ pthread_signal();
+ pthread_signal(const pthread_signal&);
+};
+
+
+} // namespace mp
+
+#endif /* mp/signal.h */
+
222 mp/sparse_array.hmpl
@@ -0,0 +1,222 @@
+//
+// mp::sparse_array
+//
+// Copyright (C) 2008-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_SPARSE_ARRAY_H__
+#define MP_SPARSE_ARRAY_H__
+
+#include <vector>
+#include <cstdlib>
+
+namespace mp {
+
+
+template <typename T>
+class sparse_array {
+public:
+ typedef size_t size_type;
+
+ sparse_array();
+ ~sparse_array();
+
+ //! Set instance of T into index.
+ inline T& set(size_type index);
+%varlen_each do |gen|
+ template <[%gen.template%]>
+ inline T& set(size_type index, [%gen.args%]);
+%end
+
+ //! Reset index.
+ inline void reset(size_type index);
+
+ //! Get the data of index.
+ inline T& data(size_type index);
+ inline const T& data(size_type index) const;
+
+ //! Get the data of index.
+ inline T* get(size_type index);
+ inline const T* get(size_type index) const;
+
+ //! Return true if index is set otherwise false.
+ inline bool test(size_type index) const;
+
+ inline size_type capacity() const;
+
+private:
+ static const size_t EXTEND_ARRAY_SIZE = 64;
+
+ struct item_t {
+ bool enable;
+ char data[sizeof(T)];
+ };
+
+ typedef std::vector<item_t*> base_array_t;
+ base_array_t base_array;
+
+private:
+ inline void* set_impl(size_type index);
+ inline void revert(size_type index);
+ inline void extend_array();
+ inline item_t& item_of(size_type index);
+ inline const item_t& item_of(size_type index) const;
+};
+
+
+template <typename T>
+sparse_array<T>::sparse_array()
+{
+ extend_array();
+}
+
+template <typename T>
+sparse_array<T>::~sparse_array()
+{
+ for(typename base_array_t::iterator it(base_array.begin()), it_end(base_array.end());
+ it != it_end;
+ ++it ) {
+ for(item_t *p(*it), *p_end(p+EXTEND_ARRAY_SIZE); p != p_end; ++p) {
+ if(p->enable) {
+ reinterpret_cast<T*>(p->data)->~T();
+ }
+ }
+ std::free(*it);
+ }
+}
+
+template <typename T>
+T& sparse_array<T>::set(size_type index)
+try {
+ return *(new (set_impl(index)) T());
+} catch (...) {
+ revert(index);
+ throw;
+}
+%varlen_each do |gen|
+template <typename T>
+template <[%gen.template%]>
+T& sparse_array<T>::set(size_type index, [%gen.args%])
+try {
+ return *(new (set_impl(index)) T([%gen.params%]));
+} catch (...) {
+ revert(index);
+ throw;
+}
+%end
+
+template <typename T>
+void sparse_array<T>::reset(size_type index)
+{
+ item_t& item(item_of(index));
+ item.enable = false;
+ reinterpret_cast<T*>(item.data)->~T();
+}
+
+template <typename T>
+T& sparse_array<T>::data(size_type index)
+{
+ return *reinterpret_cast<T*>(item_of(index).data);
+}
+
+template <typename T>
+const T& sparse_array<T>::data(size_type index) const
+{
+ return *reinterpret_cast<const T*>(item_of(index).data);
+}
+
+template <typename T>
+T* sparse_array<T>::get(size_type index)
+{
+ if( base_array.size() * EXTEND_ARRAY_SIZE > index ) {
+ item_t& item(item_of(index));
+ if( item.enable ) {
+ return reinterpret_cast<T*>(item.data);
+ }
+ }
+ return NULL;
+}
+
+template <typename T>
+const T* sparse_array<T>::get(size_type index) const
+{
+ if( base_array.size() * EXTEND_ARRAY_SIZE > index ) {
+ item_t& item(item_of(index));
+ if( item.enable ) {
+ return reinterpret_cast<const T*>(item.data);
+ }
+ }
+ return NULL;
+}
+
+template <typename T>
+bool sparse_array<T>::test(size_type index) const
+{
+ return base_array.size() * EXTEND_ARRAY_SIZE > index &&
+ item_of(index).enable;
+}
+
+template <typename T>
+typename sparse_array<T>::size_type sparse_array<T>::capacity() const
+{
+ return base_array.size() * EXTEND_ARRAY_SIZE;
+}
+
+template <typename T>
+void* sparse_array<T>::set_impl(size_type index)
+{
+ while( base_array.size() <= index / EXTEND_ARRAY_SIZE ) {
+ extend_array();
+ }
+ item_t& item(item_of(index));
+ if( item.enable ) {
+ reinterpret_cast<T*>(item.data)->~T();
+ } else {
+ item.enable = true;
+ }
+ return item.data;
+}
+
+template <typename T>
+void sparse_array<T>::revert(size_type index)
+{
+ item_of(index).enable = false;
+}
+
+template <typename T>
+void sparse_array<T>::extend_array()
+{
+ item_t* ex = (item_t*)std::calloc(EXTEND_ARRAY_SIZE, sizeof(item_t));
+ if(!ex) { throw std::bad_alloc(); }
+ base_array.push_back(ex);
+}
+
+template <typename T>
+typename sparse_array<T>::item_t& sparse_array<T>::item_of(size_type index)
+{
+ return base_array[index / EXTEND_ARRAY_SIZE][index % EXTEND_ARRAY_SIZE];
+}
+
+template <typename T>
+const typename sparse_array<T>::item_t& sparse_array<T>::item_of(size_type index) const
+{
+ return base_array[index / EXTEND_ARRAY_SIZE][index % EXTEND_ARRAY_SIZE];
+}
+
+
+} // namespace mp
+
+#endif /* mp/sparse_array.h */
+
+%# vim: filetype=mplex
280 mp/stream_buffer.h
@@ -0,0 +1,280 @@
+//
+// mpio stream_buffer
+//
+// Copyright (C) 2008-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_STREAM_BUFFER_H__
+#define MP_STREAM_BUFFER_H__
+
+#include <memory>
+#include <stdlib.h>
+#include <vector>
+#include <algorithm>
+
+#ifndef MP_STREAM_BUFFER_INITIAL_BUFFER_SIZE
+#define MP_STREAM_BUFFER_INITIAL_BUFFER_SIZE 8*1024
+#endif
+
+namespace mp {
+
+
+class stream_buffer {
+public:
+ stream_buffer(size_t initial_buffer_size = MP_STREAM_BUFFER_INITIAL_BUFFER_SIZE);
+ ~stream_buffer();
+
+public:
+ void reserve_buffer(size_t len,
+ size_t initial_buffer_size = MP_STREAM_BUFFER_INITIAL_BUFFER_SIZE);
+
+ void* buffer();
+ size_t buffer_capacity() const;
+ void buffer_filled(size_t len);
+
+ void* data();
+ size_t data_size() const;
+ void data_consumed(size_t len);
+
+ class ref {
+ public:
+ ref();
+ ref(const ref& o);
+ ~ref();
+ void clear();
+ void push(void* d);
+ void swap(ref& x);
+ private:
+ std::vector<void*> m_array;
+ struct each_incr;
+ struct each_decr;
+ };
+
+ ref release();
+ void release_to(ref* to);
+
+private:
+ char* m_buffer;
+ size_t m_used;
+ size_t m_free;
+ size_t m_off;
+ ref m_ref;
+
+private:
+ void expand_buffer(size_t len, size_t initial_buffer_size);
+
+ typedef volatile unsigned int count_t;
+ static void init_count(void* d);
+ static void decr_count(void* d);
+ static void incr_count(void* d);
+ static count_t get_count(void* d);
+
+private:
+ stream_buffer(const stream_buffer&);
+};
+
+
+
+inline void stream_buffer::init_count(void* d)
+{
+ *(volatile count_t*)d = 1;
+}
+
+inline void stream_buffer::decr_count(void* d)
+{
+ //if(--*(count_t*)d == 0) {
+ if(__sync_sub_and_fetch((count_t*)d, 1) == 0) {
+ free(d);
+ }
+}
+
+inline void stream_buffer::incr_count(void* d)
+{
+ //++*(count_t*)d;
+ __sync_add_and_fetch((count_t*)d, 1);
+}
+
+inline stream_buffer::count_t stream_buffer::get_count(void* d)
+{
+ return *(count_t*)d;
+}
+
+
+struct stream_buffer::ref::each_incr {
+ void operator() (void* d)
+ {
+ stream_buffer::incr_count(d);
+ }
+};
+
+struct stream_buffer::ref::each_decr {
+ void operator() (void* d)
+ {
+ stream_buffer::decr_count(d);
+ }
+};
+
+inline stream_buffer::ref::ref() { }
+
+inline stream_buffer::ref::ref(const ref& o) :
+ m_array(m_array)
+{
+ std::for_each(m_array.begin(), m_array.end(), each_incr());
+}
+
+inline void stream_buffer::ref::clear()
+{
+ std::for_each(m_array.begin(), m_array.end(), each_decr());
+ m_array.clear();
+}
+
+inline stream_buffer::ref::~ref()
+{
+ clear();
+}
+
+inline void stream_buffer::ref::push(void* d)
+{
+ m_array.push_back(d);
+ incr_count(d);
+}
+
+inline void stream_buffer::ref::swap(ref& x)
+{
+ m_array.swap(x.m_array);
+}
+
+
+inline stream_buffer::stream_buffer(size_t initial_buffer_size) :
+ m_buffer(NULL),
+ m_used(0),
+ m_free(0),
+ m_off(0)
+{
+ const size_t initsz = std::max(initial_buffer_size, sizeof(count_t));
+
+ m_buffer = (char*)::malloc(initsz);
+ if(!m_buffer) { throw std::bad_alloc(); }
+ init_count(m_buffer);
+
+ m_used = sizeof(count_t);
+ m_free = initsz - m_used;
+ m_off = sizeof(count_t);
+}
+
+inline stream_buffer::~stream_buffer()
+{
+ decr_count(m_buffer);
+}
+
+inline void* stream_buffer::buffer()
+{
+ return m_buffer + m_used;
+}
+
+inline size_t stream_buffer::buffer_capacity() const
+{
+ return m_free;
+}
+
+inline void stream_buffer::buffer_filled(size_t len)
+{
+ m_used += len;
+ m_free -= len;
+}
+
+inline void* stream_buffer::data()
+{
+ return m_buffer + m_off;
+}
+
+inline size_t stream_buffer::data_size() const
+{
+ return m_used - m_off;
+}
+
+inline void stream_buffer::data_consumed(size_t len)
+{
+ m_off += len;
+}
+
+
+inline stream_buffer::ref stream_buffer::release()
+{
+ ref r;
+ r.swap(m_ref);
+ return r;
+}
+
+inline void stream_buffer::release_to(ref* to)
+{
+ m_ref.push(m_buffer);
+ to->swap(m_ref);
+ m_ref.clear();
+}
+
+inline void stream_buffer::reserve_buffer(size_t len, size_t initial_buffer_size)
+{
+ if(m_used == m_off && get_count(m_buffer) == 1) {
+ // rewind buffer
+ m_free += m_used - sizeof(count_t);
+ m_used = sizeof(count_t);
+ m_off = sizeof(count_t);
+ }
+ if(m_free < len) {
+ expand_buffer(len, initial_buffer_size);
+ }
+}
+
+inline void stream_buffer::expand_buffer(size_t len, size_t initial_buffer_size)
+{
+ if(m_off == sizeof(count_t)) {
+ size_t next_size = (m_used + m_free) * 2;
+ while(next_size < len + m_used) { next_size *= 2; }
+
+ char* tmp = (char*)::realloc(m_buffer, next_size);
+ if(!tmp) { throw std::bad_alloc(); }
+
+ m_buffer = tmp;
+ m_free = next_size - m_used;
+
+ } else {
+ const size_t initsz = std::max(initial_buffer_size, sizeof(count_t));
+
+ size_t next_size = initsz; // include sizeof(count_t)
+ size_t not_used = m_used - m_off;
+ while(next_size < len + not_used + sizeof(count_t)) { next_size *= 2; }
+
+ char* tmp = (char*)::malloc(next_size);
+ if(!tmp) { throw std::bad_alloc(); }
+ init_count(tmp);
+
+ try {
+ m_ref.push(m_buffer);
+ } catch (...) { free(tmp); throw; }
+
+ memcpy(tmp+sizeof(count_t), m_buffer+m_off, not_used);
+
+ m_buffer = tmp;
+ m_used = not_used + sizeof(count_t);
+ m_free = next_size - m_used;
+ m_off = sizeof(count_t);
+ }
+}
+
+
+} // namespace mp
+
+#endif /* mp/stream_buffer.h */
+
126 mp/sync.hmpl
@@ -0,0 +1,126 @@
+//
+// mpio sync
+//
+// Copyright (C) 2009-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_SYNC_H__
+#define MP_SYNC_H__
+
+#include "mp/pthread.h"
+
+namespace mp {
+
+
+template <typename T>
+class sync {
+public:
+ sync() : m_obj() { }
+%varlen_each do |gen|
+ template <[%gen.template%]>
+ sync([%gen.args%]) : m_obj([%gen.params%]) { }
+%end
+
+ ~sync() { }
+
+ T& unsafe_ref() { return m_obj; }
+ const T& unsafe_ref() const { return m_obj; }
+
+ class ref {
+ public:
+ ref(sync<T>& obj) : m_ref(NULL)
+ {
+ obj.m_mutex.lock();
+ m_ref = &obj;
+ }
+
+ ref() : m_ref(NULL) { }
+
+ ~ref() { reset(); }
+
+ void reset()
+ {
+ if(m_ref) {
+ m_ref->m_mutex.unlock();
+ m_ref = NULL;
+ }
+ }
+
+ void reset(sync<T>& obj)
+ {
+ reset();
+ obj.m_mutex.lock();
+ m_ref = &obj;
+ }
+
+ void swap(sync<T>& obj)
+ {
+ sync<T>* tmp = m_ref;
+ m_ref = obj.m_ref;
+ obj.m_ref = tmp;
+ }
+
+ T& operator*() { return m_ref->m_obj; }
+ T* operator->() { return &operator*(); }
+ const T& operator*() const { return m_ref->m_obj; }
+ const T* operator->() const { return &operator*(); }
+
+ operator bool() const { return m_ref != NULL; }
+
+ protected:
+ sync<T>* m_ref;
+
+ private:
+ ref(const ref&);
+ };
+
+ class auto_ref : public ref {
+ public:
+ auto_ref(sync<T>& obj) : ref(obj) { }
+ auto_ref() { }
+ ~auto_ref() { }
+
+ auto_ref(auto_ref& o)
+ {
+ ref::m_ref = o.m_ref;
+ o.m_ref = NULL;
+ }
+
+ auto_ref& operator= (auto_ref& o)
+ {
+ auto_ref(o).swap(*this);
+ return *this;
+ }
+ };
+
+ auto_ref lock()
+ {
+ return auto_ref(*this);
+ }
+
+private:
+ T m_obj;
+ pthread_mutex m_mutex;
+ friend class ref;
+
+private:
+ sync(const sync&);
+};
+
+
+} // namespace mp
+
+#endif /* mp/sync.h */
+
+%# vim: filetype=mplex
182 mp/tls_set.h
@@ -0,0 +1,182 @@
+//
+// mpio tls_set
+//
+// Copyright (C) 2008-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_TLS_SET_H__
+#define MP_TLS_SET_H__
+#ifdef MP_EXPERIMENTAL
+
+#include "mp/pthread.h"
+#include "mp/sync.h"
+#include <memory>
+#include <vector>
+
+namespace mp {
+
+
+class pthread_scoped_lock_multi {
+public:
+ pthread_scoped_lock_multi() : m_vec(NULL) { }
+
+ pthread_scoped_lock_multi(size_t size) :
+ m_vec(new pthread_scoped_lock[size]) { }
+
+ ~pthread_scoped_lock_multi() { delete[] m_vec; }
+
+ void reset(size_t size)
+ {
+ if(m_vec) { delete[] m_vec; }
+ m_vec = NULL;
+ m_vec = new pthread_scoped_lock[size];
+ }
+
+ pthread_scoped_lock& operator[] (size_t index)
+ {
+ return m_vec[index];
+ }
+
+ const pthread_scoped_lock& operator[] (size_t index) const
+ {
+ return m_vec[index];
+ }
+
+private:
+ pthread_scoped_lock* m_vec;
+
+private:
+ pthread_scoped_lock_multi(const pthread_scoped_lock_multi&);
+};
+
+
+template <typename T>
+class tls_set {
+public:
+ tls_set()
+ {
+ int err = pthread_key_create(&m_key, &mp::object_destructor<T>);
+ if(err) { throw pthread_error(err, "failed to create TLS key"); }
+ }
+
+ ~tls_set()
+ { }
+
+ void init_thread(const T& data = T())
+ {
+ all_vec_ref ref(m_all_vec);
+
+ std::auto_ptr<element> e(new element(data));
+
+ ref->push_back(e.get());
+
+ int err = pthread_setspecific(m_key, (void*)e.get());
+ if(err) {
+ ref->pop_back();
+ throw pthread_error(err, "failed to init TLS");
+ }
+
+ e.release();
+ }
+
+ void update_self(const T& data)
+ {
+ element* e = (element*)pthread_getspecific(m_key);
+ pthread_scoped_lock lk(e->mutex);
+ e->data = data;
+ }
+
+ T& get_self(pthread_scoped_lock* lk)
+ {
+ element* e = (element*)pthread_getspecific(m_key);
+ lk->relock(e->mutex);
+ return e->data;
+ }
+
+ T& get_self(const pthread_scoped_lock_multi& mlk)
+ {
+ element* e = (element*)pthread_getspecific(m_key);
+ return e->data;
+ }
+
+ void update_all(const T& data)
+ {
+ all_vec_ref ref(m_all_vec);
+ for(typename all_vec_t::iterator it(ref->begin()),
+ it_end(ref->end()); it != it_end; ++it) {
+ pthread_scoped_lock lk(it->mutex);
+ it->data = data;
+ }
+ }
+
+ template <typename F>
+ void get_all(F func)
+ {
+ all_vec_ref ref(m_all_vec);
+ for(typename all_vec_t::iterator it(ref->begin()),
+ it_end(ref->end()); it != it_end; ++it) {
+ pthread_scoped_lock lk(it->mutex);
+ func(it->data);
+ }
+ }
+
+ void update_all(const T& data, const pthread_scoped_lock_multi& mlk)
+ {
+ all_vec_ref ref(m_all_vec);
+ for(typename all_vec_t::iterator it(ref->begin()),
+ it_end(ref->end()); it != it_end; ++it) {
+ it->data = data;
+ }
+ }
+
+ template <typename F>
+ void get_all(F func, const pthread_scoped_lock_multi& mlk)
+ {
+ all_vec_ref ref(m_all_vec);
+ for(typename all_vec_t::iterator it(ref->begin()),
+ it_end(ref->end()); it != it_end; ++it) {
+ func(it->data);
+ }
+ }
+
+ void lock_all(pthread_scoped_lock_multi* mlk)
+ {
+ all_vec_ref ref(m_all_vec);
+ mlk->reset(ref->size());
+ for(size_t i=0; i < ref->size(); ++i) {
+ (*mlk)[i].relock((*ref)[i]->mutex);
+ }
+ }
+
+private:
+ struct element {
+ element(const T& data) : data(data) { }
+ ~element() { }
+ T data;
+ pthread_mutex mutex;
+ };
+
+ pthread_key_t m_key;
+
+ typedef std::vector<element*> all_vec_t;
+ typedef typename mp::sync<all_vec_t>::ref all_vec_ref;
+ mp::sync<all_vec_t> m_all_vec;
+};
+
+
+} // namespace mp
+
+#endif /* MP_EXPERIMENTAL */
+#endif /* mp/tls_set.h */
+
40 mp/utilize.h
@@ -0,0 +1,40 @@
+//
+// mpio utilize
+//
+// Copyright (C) 2009-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_UTILIZE_H__
+#define MP_UTILIZE_H__
+
+
+#define MP_UTILIZE \
+ struct mp_util; \
+ friend struct mp_util
+
+#define MP_UTIL_DEF(name) \
+ struct name::mp_util : public name
+
+#define MP_UTIL_IMPL(name) \
+ name::mp_util
+
+#define MP_UTIL \
+ (*static_cast<mp_util*>(this))
+
+#define MP_UTIL_FROM(self) \
+ (*static_cast<mp_util*>(self))
+
+
+#endif /* mp/utilze.h */
+
412 mp/wavy.hmpl
@@ -0,0 +1,412 @@
+//
+// mpio wavy
+//
+// Copyright (C) 2008-2010 FURUHASHI Sadayuki
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef MP_WAVY_H__
+#define MP_WAVY_H__
+
+#include "mp/functional.h"
+#include "mp/memory.h"
+#include "mp/pthread.h"
+#include "mp/object_delete.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <time.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <memory>
+
+namespace mp {
+namespace wavy {
+
+
+class basic_handler;
+class handler;
+class event;
+class xfer;
+typedef shared_ptr<basic_handler> shared_handler;
+typedef weak_ptr<basic_handler> weak_handler;
+
+
+class loop {
+public:
+ typedef mp::wavy::basic_handler basic_handler;
+ typedef mp::wavy::handler handler;
+ typedef mp::wavy::event event;
+
+ loop();
+ loop(function<void ()> thread_init_func);
+
+ ~loop();
+
+ void start(size_t num);
+
+ void run(size_t num); // run = start + join
+
+ bool is_running() const;
+
+ void run_once();
+
+ void end();
+ bool is_end() const;
+
+ void join();
+ void detach();
+
+ void add_thread(size_t num);
+
+
+
+ typedef function<void (int fd, int err)> connect_callback_t;
+
+ void connect(
+ int socket_family, int socket_type, int protocol,
+ const sockaddr* addr, socklen_t addrlen,
+ const timespec* timeout, connect_callback_t callback);
+
+ void connect(
+ int socket_family, int socket_type, int protocol,
+ const sockaddr* addr, socklen_t addrlen,
+ double timeout_sec, connect_callback_t callback);
+
+
+ typedef function<void (int fd, int err)> listen_callback_t;
+
+ int listen(
+ int socket_family, int socket_type, int protocol,
+ const sockaddr* addr, socklen_t addrlen,
+ listen_callback_t callback,
+ int backlog = 1024);
+
+
+ typedef function<bool ()> timer_callback_t;
+
+ int add_timer(const timespec* value, const timespec* interval,
+ timer_callback_t callback);
+
+ int add_timer(double value_sec, double interval_sec,
+ timer_callback_t callback);
+
+ void remove_timer(int ident);
+
+
+ typedef function<bool (int signo)> signal_callback_t;
+
+ int add_signal(int signo, signal_callback_t callback);
+
+ void remove_signal(int ident);
+
+
+
+ typedef void (*finalize_t)(void* user);
+
+
+ void write(int fd, const void* buf, size_t size);
+
+ void write(int fd, const void* buf, size_t size,
+ finalize_t fin, void* user);
+
+ template <typename T>
+ void write(int fd, const void* buf, size_t size,
+ std::auto_ptr<T>& fin);
+
+ template <typename T>
+ void write(int fd, const void* buf, size_t size,
+ mp::shared_ptr<T> fin);
+
+
+ void writev(int fd, const struct iovec* vec, size_t veclen,
+ finalize_t fin, void* user);
+
+ template <typename T>
+ void writev(int fd, const struct iovec* vec, size_t veclen,
+ std::auto_ptr<T>& fin);
+
+ template <typename T>
+ void writev(int fd, const struct iovec* vec, size_t veclen,
+ mp::shared_ptr<T> fin);
+
+
+ void sendfile(int fd, int infd, uint64_t off, size_t size,
+ finalize_t fin, void* user);
+
+ void hsendfile(int fd,
+ const void* header, size_t header_size,
+ int infd, uint64_t off, size_t size,
+ finalize_t fin, void* user);
+
+ void hvsendfile(int fd,
+ const struct iovec* header_vec, size_t header_veclen,
+ int infd, uint64_t off, size_t size,
+ finalize_t fin, void* user);
+
+
+ void commit(int fd, xfer* xf);
+
+
+
+ template <typename Handler>
+ shared_ptr<Handler> add_handler();
+%varlen_each do |gen|
+ template <typename Handler, [%gen.template%]>
+ shared_ptr<Handler> add_handler([%gen.args%]);
+%end
+
+
+ template <typename F>
+ void submit(F f);
+%varlen_each do |gen|
+ template <typename F, [%gen.template%]>
+ void submit(F f, [%gen.args%]);
+%end
+
+
+private:
+ shared_handler add_handler_impl(shared_handler sh);
+
+ typedef function<void ()> task_t;
+ void submit_impl(task_t f);
+
+private:
+ void* m_impl;
+
+ loop(const loop&);
+};
+
+
+class event {
+protected:
+ event() { }
+ ~event() { }
+public:
+ void more();
+ void next();
+ void remove();
+private:
+ event(const event&);
+};
+
+
+class xfer {
+public:
+ xfer();
+ ~xfer();
+
+ typedef loop::finalize_t finalize_t;
+
+ void push_write(const void* buf, size_t size);
+
+ void push_writev(const struct iovec* vec, size_t veclen);
+
+ void push_sendfile(int infd, uint64_t off, size_t len);
+
+ void push_finalize(finalize_t fin, void* user);
+
+ template <typename T>
+ void push_finalize(std::auto_ptr<T> fin);
+
+ template <typename T>
+ void push_finalize(mp::shared_ptr<T> fin);
+
+ bool empty() const;
+
+ void clear();
+
+ void migrate(xfer* to);
+
+protected:
+ char* m_head;
+ char* m_tail;
+ size_t m_free;
+
+ void reserve(size_t reqsz);
+
+private:
+ xfer(const xfer&);
+};
+
+
+struct basic_handler {
+public:
+ typedef bool (*callback_t)(basic_handler*, event&);
+
+ template <typename IMPL>
+ basic_handler(int ident, IMPL* self) :
+ m_ident(ident), m_callback(&static_callback<IMPL>) { }
+
+ basic_handler(int ident, callback_t callback) :
+ m_ident(ident), m_callback(callback) { }
+
+ virtual ~basic_handler() { }
+
+ int ident() const { return m_ident; }
+
+ int fd() const { return ident(); }
+
+ bool operator() (event& e);
+
+private:
+ int m_ident;
+
+ callback_t m_callback;
+
+private:
+ template <typename IMPL>
+ static bool static_callback(basic_handler* self, event& e)
+ {
+ return (*static_cast<IMPL*>(self))(e);
+ }
+
+ basic_handler();
+ basic_handler(const basic_handler&);
+};
+
+
+struct handler : public mp::enable_shared_from_this<handler>, public basic_handler {
+public:
+ handler(int fd) : basic_handler(fd, &callback_on_read) { }
+
+ ~handler() { ::close(fd()); }
+
+ virtual void on_read(event& e) = 0;
+
+public:
+ template <typename IMPL>
+ shared_ptr<IMPL> shared_self()
+ {
+ return static_pointer_cast<IMPL>(enable_shared_from_this<handler>::shared_from_this());
+ }
+
+ template <typename IMPL>
+ shared_ptr<IMPL const> shared_self() const
+ {
+ return static_pointer_cast<IMPL>(enable_shared_from_this<handler>::shared_from_this());
+ }
+
+private:
+ static inline bool callback_on_read(basic_handler* self, event& e)
+ {
+ static_cast<handler*>(self)->on_read(e);
+ return true;
+ }
+ friend class basic_handler;
+};
+
+
+inline bool basic_handler::operator() (event& e)
+{
+ if(m_callback == handler::callback_on_read) {
+ return handler::callback_on_read(this, e);
+ } else {
+ return m_callback(this, e);
+ }
+}
+
+
+template <typename Handler>
+shared_ptr<Handler> loop::add_handler()
+ { return static_pointer_cast<Handler>(add_handler_impl(
+ shared_ptr<Handler>(new Handler())) ); }
+%varlen_each do |gen|
+template <typename Handler, [%gen.template%]>
+shared_ptr<Handler> loop::add_handler([%gen.args%])
+ { return static_pointer_cast<Handler>(add_handler_impl(
+ shared_ptr<Handler>(new Handler([%gen.params%]))) ); }
+%end
+
+template <typename F>
+inline void loop::submit(F f)
+ { submit_impl(task_t(f)); }
+%varlen_each do |gen|
+template <typename F, [%gen.template%]>
+inline void loop::submit(F f, [%gen.args%])
+ { submit_impl(bind(f, [%gen.params%])); }
+%end
+