• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

C++ベースのLightweightなHTTPサーバー


Commit MetaInfo

Revision2a7cb64db6481cc02ffb97efbe3100b01faed698 (tree)
Time2013-01-20 10:51:35
AuthorMichio Hirai <smg_ykz@user...>
CommiterMichio Hirai

Log Message

[Function] New introduction of cm::VectorSocket class to realize gather-write operation.

Change Summary

Incremental Difference

--- a/cm/CMakeLists.txt
+++ b/cm/CMakeLists.txt
@@ -22,6 +22,7 @@ cxx_library_static(cm_socket ""
2222 cm_socket_server.cpp
2323 cm_socket_client.cpp
2424 cm_socket.cpp
25+ cm_vector_socket.cpp
2526 )
2627
2728 gmock_executable(cm_thread_test "cm_thread"
@@ -38,5 +39,9 @@ gmock_executable(cm_socket_server_test "cm_socket;cm_event"
3839 test/cm_socket_server_client_test.cpp
3940 )
4041
42+gmock_executable(cm_vector_socket_test "cm_socket;"
43+ test/cm_vector_socket_test.cpp
44+)
45+
4146 enable_coverage()
4247
--- a/cm/cm_socket.cpp
+++ b/cm/cm_socket.cpp
@@ -7,16 +7,16 @@
77 namespace cm {
88
99 Socket::Socket()
10- : fd_(-1), need_open_(true)
10+ : fd_(-1)
1111 {}
1212
1313 Socket::Socket(int fd)
14- : fd_(fd), need_open_(false)
14+ : fd_(fd)
1515 {}
1616
1717 Socket::~Socket()
1818 {
19- if ((!need_open_) && (fd_ >= 0)) {
19+ if (fd_ >= 0) {
2020 close(fd_);
2121 fd_ = -1;
2222 }
@@ -71,6 +71,13 @@ int Socket::getFD() const
7171 return fd_;
7272 }
7373
74+int Socket::release()
75+{
76+ int fd_to_return = fd_;
77+ fd_ = -1;
78+ return fd_to_return;
79+}
80+
7481 SocketIf* Socket::doClone(int fd) const
7582 {
7683 return new Socket(fd);
--- /dev/null
+++ b/cm/cm_vector_socket.cpp
@@ -0,0 +1,29 @@
1+
2+#include <cassert>
3+
4+#include "mt_shim_clear_memory.h"
5+#include "cm_vector_socket.h"
6+
7+namespace cm {
8+
9+VectorSocket::VectorSocket(int fd)
10+ : fd_(fd)
11+{}
12+
13+bool VectorSocket::writev(size_t& bytes_written, const IOVectorBase& vector, size_t skip_bytes)
14+{
15+ assert(fd_ >= 0);
16+
17+ struct iovec iovector[MAX_IOVEC_COUNT];
18+
19+ mt::clearMemory(iovector);
20+
21+ vector.setToVector(iovector);
22+
23+ bytes_written = ::writev(fd_, iovector, vector.getCount());
24+
25+ return true;
26+}
27+
28+
29+} // namespace cm
--- a/cm/test/cm_socket_server_client_test.cpp
+++ b/cm/test/cm_socket_server_client_test.cpp
@@ -71,6 +71,7 @@ public:
7171
7272 MOCK_METHOD3(read, bool(size_t& bytes_read, void* buf, size_t size_to_read));
7373 MOCK_METHOD3(write, bool(size_t& bytes_read, const void* buf, size_t size_to_write));
74+ MOCK_METHOD0(release, int());
7475
7576 virtual int getFD() const
7677 {
--- /dev/null
+++ b/cm/test/cm_vector_socket_test.cpp
@@ -0,0 +1,79 @@
1+
2+#include <unistd.h>
3+
4+#include "gmock/gmock.h"
5+
6+#include "mt_typelist_algo_utility.h"
7+#include "mt_shim_clear_memory.h"
8+#include "cm_vector_socket.h"
9+#include "cm_socket.h"
10+
11+namespace {
12+
13+#pragma GCC diagnostic ignored "-Weffc++"
14+struct StringBufferMock
15+{
16+ MOCK_CONST_METHOD0(getString, const char*());
17+};
18+#pragma GCC diagnostic warning "-Weffc++"
19+
20+struct RFRelease
21+{
22+ RFRelease(StringBufferMock* mock_ptr)
23+ : mock_ptr_(mock_ptr)
24+ {}
25+
26+ void operator()()
27+ {
28+ delete mock_ptr_;
29+ }
30+
31+ StringBufferMock* mock_ptr_;
32+};
33+
34+static const char string1[] = "hello";
35+static const char string2[] = " ";
36+static const char string3[] = "world ";
37+static const char string4[] = "!!!!";
38+
39+static const char string_for_mock[] = "[good by cruel world --]";
40+
41+TEST(CmVectorSocketTest, simple)
42+{
43+ StringBufferMock* mock = new StringBufferMock;
44+
45+ EXPECT_CALL(*mock, getString())
46+ .WillOnce(::testing::Return(string_for_mock));
47+
48+ const cm::IOVectorBase& iov
49+ = cm::IOVec()(string1, sizeof(string1) - 1)
50+ (string2, sizeof(string2) - 1)
51+ (string3, sizeof(string3) - 1)
52+ (string4, sizeof(string4) - 1)
53+ (mock->getString(), sizeof(string_for_mock) - 1, RFRelease(mock));
54+
55+ int pipe_fds[2];
56+ int retval = pipe(pipe_fds);
57+ EXPECT_EQ(retval, 0);
58+
59+ cm::VectorSocket write_socket(pipe_fds[1]);
60+ cm::Socket read_socket(pipe_fds[0]);
61+
62+ size_t bytes_written = 0u;
63+ bool ret = write_socket.writev(bytes_written, iov);
64+
65+ EXPECT_EQ(ret, true);
66+
67+ size_t total_bytes_written = sizeof(string1) - 1 + sizeof(string2) - 1 + sizeof(string3) - 1 + sizeof(string4) - 1 + sizeof(string_for_mock) - 1;
68+ EXPECT_EQ(bytes_written, total_bytes_written);
69+
70+ size_t bytes_read = 0u;
71+ char recv_buffer[1024];
72+ mt::clearMemory(recv_buffer);
73+ ret = read_socket.read(bytes_read, recv_buffer, sizeof(recv_buffer));
74+
75+ EXPECT_EQ(ret, true);
76+ EXPECT_EQ(bytes_read, total_bytes_written);
77+}
78+
79+} // namespace
--- /dev/null
+++ b/inc/cm_io_vector.h
@@ -0,0 +1,139 @@
1+
2+#ifndef INC_CM_IO_VECTOR_H_
3+#define INC_CM_IO_VECTOR_H_
4+
5+#include "mt_static_assert.h"
6+#include "mt_member_detector.h"
7+#include "mt_typelist.h"
8+#include "mt_typelist_algo_utility.h"
9+
10+namespace cm {
11+
12+struct IOVectorBase
13+{
14+ virtual ~IOVectorBase()
15+ {}
16+
17+ virtual void setToVector(struct iovec*) const = 0;
18+
19+ virtual size_t getCount() const = 0;
20+};
21+
22+template <typename TL, typename TLList>
23+struct IOVectorChain : IOVectorBase
24+{
25+public:
26+ typedef typename TL::Head T;
27+ typedef typename TL::Tail RF;
28+
29+ static const size_t LAYERED_COUNT = IOVectorChain<typename TLList::Head, typename TLList::Tail>::LAYERED_COUNT + 1;
30+
31+ IOVectorChain(const IOVectorChain<TL, TLList>& rhs)
32+ : ptr_(rhs.ptr_), size_(rhs.size_), release_functor_(rhs.release_functor_), tail_(rhs.tail_), should_release_(rhs.should_release_)
33+ {
34+ rhs.should_release_ = false;
35+ }
36+
37+ IOVectorChain(const T* ptr, size_t size, RF release_functor, const IOVectorChain<typename TLList::Head, typename TLList::Tail>& obj)
38+ : ptr_(ptr), size_(size), release_functor_(release_functor), tail_(obj), should_release_(true)
39+ {}
40+
41+ template <typename Functor>
42+ void performReleaseFunctor(Functor& func, typename mt::EnableIf<mt::HasFunctorOperator<Functor>::value>::Result* = 0)
43+ {
44+ release_functor_();
45+ }
46+
47+ template <typename Functor>
48+ void performReleaseFunctor(Functor&, typename mt::EnableIf<!mt::HasFunctorOperator<Functor>::value>::Result* = 0)
49+ {
50+ }
51+
52+ virtual ~IOVectorChain()
53+ {
54+ if (should_release_) {
55+ performReleaseFunctor(release_functor_);
56+ }
57+ }
58+
59+ void setToVector(struct iovec* iovec_ptr) const
60+ {
61+ STATIC_ASSERT(LAYERED_COUNT >= 1);
62+ const size_t offset = LAYERED_COUNT - 1;
63+ iovec_ptr[offset].iov_base = const_cast<void*>(reinterpret_cast<const void*>(ptr_));
64+ iovec_ptr[offset].iov_len = size_;
65+ tail_.setToVector(iovec_ptr);
66+ }
67+
68+ virtual size_t getCount() const
69+ {
70+ return LAYERED_COUNT;
71+ }
72+
73+ template <typename X, typename XRF>
74+ IOVectorChain< mt::Typelist<X, XRF>, mt::Typelist<TL, TLList> >
75+ operator()(const X* ptr, size_t size, XRF x_release_functor)
76+ {
77+ return IOVectorChain< mt::Typelist<X, XRF>, mt::Typelist<TL, TLList> >(ptr, size, x_release_functor, *this);
78+ }
79+
80+ template <typename X>
81+ IOVectorChain< mt::Typelist<X, mt::NullType>, mt::Typelist<TL, TLList> > operator()(const X* ptr, size_t size)
82+ {
83+ return IOVectorChain< mt::Typelist<X, mt::NullType>, mt::Typelist<TL, TLList> >(ptr, size, mt::getNullType(), *this);
84+ }
85+
86+private:
87+ const T* ptr_;
88+ size_t size_;
89+ RF release_functor_;
90+ const IOVectorChain<typename TLList::Head, typename TLList::Tail> tail_;
91+ mutable bool should_release_;
92+};
93+
94+template <>
95+struct IOVectorChain<mt::NullType, mt::NullType>
96+{
97+public:
98+ static const size_t LAYERED_COUNT = 0;
99+
100+ IOVectorChain()
101+ : should_release_(true)
102+ {}
103+
104+ IOVectorChain(const IOVectorChain<mt::NullType, mt::NullType>& rhs)
105+ : should_release_(rhs.should_release_)
106+ {
107+ rhs.should_release_ = false;
108+ }
109+
110+ virtual ~IOVectorChain()
111+ {}
112+
113+ void setToVector(struct iovec*) const
114+ {
115+ return;
116+ }
117+
118+ template <typename T, typename RF>
119+ IOVectorChain< mt::Typelist<T, RF>, mt::Typelist<mt::NullType, mt::NullType> >
120+ operator()(const T* ptr, size_t size, RF release_functor)
121+ {
122+ return IOVectorChain< mt::Typelist<T, RF>, mt::Typelist<mt::NullType, mt::NullType> >(ptr, size, release_functor, *this);
123+ }
124+
125+ template <typename T>
126+ IOVectorChain< mt::Typelist<T, mt::NullType>, mt::Typelist<mt::NullType, mt::NullType> >
127+ operator()(const T* ptr, size_t size)
128+ {
129+ return IOVectorChain< mt::Typelist<T, mt::NullType>, mt::Typelist<mt::NullType, mt::NullType> >(ptr, size, mt::getNullType(), *this);
130+ }
131+
132+ mutable bool should_release_;
133+};
134+
135+typedef IOVectorChain<mt::NullType, mt::NullType> IOVec;
136+
137+
138+} // namespace cm
139+#endif // INC_CM_IO_VECTOR_H_
--- a/inc/cm_socket.h
+++ b/inc/cm_socket.h
@@ -3,6 +3,8 @@
33 #define INC_CM_SOCKET_H_
44
55 #include "cm_socket_if.h"
6+#include "mt_mpl.h"
7+#include "mt_member_detector.h"
68
79 namespace cm {
810
@@ -12,6 +14,11 @@ public:
1214 Socket();
1315 Socket(int fd);
1416
17+ template <typename SocketType>
18+ Socket(SocketType& socket, typename mt::EnableIf<mt::HasReleaseMethod<SocketType>::value>::Result* = 0)
19+ : fd_(socket.release())
20+ {}
21+
1522 virtual ~Socket();
1623
1724 virtual bool read(size_t& bytes_read, void* buf, size_t size_to_read);
@@ -19,11 +26,11 @@ public:
1926
2027 virtual int getFD() const;
2128
29+ virtual int release();
2230 private:
2331 virtual SocketIf* doClone(int fd) const;
2432
2533 int fd_;
26- bool need_open_;
2734 };
2835
2936 } // namespace cm
--- a/inc/cm_socket_if.h
+++ b/inc/cm_socket_if.h
@@ -22,6 +22,8 @@ public:
2222 return mt::AutoPtr<SocketIf>(this->doClone(fd));
2323 }
2424
25+ virtual int release() = 0;
26+
2527 protected:
2628 virtual SocketIf* doClone(int fd) const = 0;
2729
--- a/inc/cm_socket_mock.h
+++ b/inc/cm_socket_mock.h
@@ -63,6 +63,8 @@ public:
6363 return false;
6464 }
6565
66+ MOCK_METHOD0(release, int());
67+
6668 MOCK_METHOD3(write, bool(size_t& bytes_written, const void* buf, size_t size_to_write));
6769 MOCK_CONST_METHOD1(doClone, SocketIf*(int fd));
6870
--- /dev/null
+++ b/inc/cm_vector_socket.h
@@ -0,0 +1,36 @@
1+#ifndef INC_CM_VECTOR_SOCKET_H_
2+#define INC_CM_VECTOR_SOCKET_H_
3+
4+#include <unistd.h>
5+#include <sys/uio.h>
6+#include <vector>
7+#include <iostream>
8+
9+#include "mt_member_detector.h"
10+#include "mt_mpl.h"
11+#include "cm_io_vector.h"
12+
13+namespace cm {
14+
15+class VectorSocket
16+{
17+public:
18+ VectorSocket(int fd);
19+
20+ template <typename SocketType>
21+ VectorSocket(SocketType& socket, typename mt::EnableIf<mt::HasReleaseMethod<SocketType>::value>::Result* = 0)
22+ : fd_(socket.release())
23+ {}
24+
25+ static const int MAX_IOVEC_COUNT = 64;
26+
27+ bool writev(size_t& bytes_written, const IOVectorBase& vector, size_t skip_bytes = 0u);
28+ // bool readv(size_t& bytes_read, IOVector<T>& vector);
29+
30+private:
31+ int fd_;
32+};
33+
34+} // namespace cm
35+
36+#endif // INC_CM_VECTOR_SOCKET_H_
--- a/inc/mt_auto_ptr.h
+++ b/inc/mt_auto_ptr.h
@@ -30,9 +30,8 @@ public:
3030 {}
3131
3232 AutoPtr(AutoPtr<T>& rhs)
33- : raw_ptr_(rhs.get())
33+ : raw_ptr_(rhs.release())
3434 {
35- rhs.release();
3635 }
3736
3837 AutoPtr(AutoPtrRef<T> ref)
@@ -49,9 +48,7 @@ public:
4948
5049 operator AutoPtrRef<T> ()
5150 {
52- T* ptr = this->get();
53- this->release();
54- return AutoPtrRef<T>(ptr);
51+ return AutoPtrRef<T>(release());
5552 }
5653
5754 ~AutoPtr()
@@ -59,9 +56,11 @@ public:
5956 reset();
6057 }
6158
62- void release()
59+ T* release()
6360 {
61+ T* ptr_to_return = raw_ptr_;
6462 raw_ptr_ = 0;
63+ return ptr_to_return;
6564 }
6665
6766 void set(T* new_ptr)
@@ -117,9 +116,6 @@ public:
117116 }
118117
119118 private:
120- // Won't allow conventional copy semantics from another const AutoPtr object.
121-// AutoPtr(const AutoPtr& rhs);
122-// AutoPtr& operator=(const AutoPtr& rhs);
123119
124120 T* raw_ptr_;
125121 };
--- /dev/null
+++ b/inc/mt_member_detector.h
@@ -0,0 +1,37 @@
1+
2+#ifndef INC_MT_MEMBER_DETECTOR_H_
3+#define INC_MT_MEMBER_DETECTOR_H_
4+
5+#include "mt_sfinae.h"
6+
7+namespace mt {
8+
9+// Meta function to detect whether parameterized type T has void operator() member function.
10+template <typename T>
11+struct HasFunctorOperator
12+{
13+ template <typename X>
14+ static mt::YesTypeWithNonConstMemberMethodNoArg<X, void, &X::operator()> test(X*);
15+
16+ template <typename X>
17+ static mt::NoType test(...);
18+
19+ static const bool value = sizeof(test<T>(0)) != sizeof(mt::NoType);
20+};
21+
22+// Meta function to detect whether parameterized type T has int relase() member function
23+template <typename T>
24+struct HasReleaseMethod
25+{
26+ template <typename X>
27+ static mt::YesTypeWithNonConstMemberMethodNoArg<X, int, &X::release> test(T*);
28+
29+ template <typename X>
30+ static mt::NoType test(...);
31+
32+ static const bool value = sizeof(test<T>(0)) != sizeof(mt::NoType);
33+};
34+
35+} // namespace mt
36+
37+#endif // INC_MT_MEMBER_DETECTOR_H_
--- a/inc/mt_static_assert.h
+++ b/inc/mt_static_assert.h
@@ -16,6 +16,6 @@ struct StaticAssert<true>
1616
1717 } // namespace mt
1818
19-#define STATIC_ASSERT(cond) mt::unuseWithMessage(StaticAssert< (cond) >(), #cond)
19+#define STATIC_ASSERT(cond) mt::unuseWithMessage(mt::StaticAssert< (cond) >(), #cond)
2020
2121 #endif // INC_MT_STATIC_ASSERT_H_